From cb74897da965d78369711bb484226639d8d5a4db Mon Sep 17 00:00:00 2001 From: Florian Lentsch Date: Fri, 11 Oct 2024 12:48:33 +0200 Subject: [PATCH] Started with #1058 See https://github.com/foodcoopsat/foodsoft_hackathon for open issues --- .eslintrc.js | 14 + .rubocop_todo.yml | 222 +- Gemfile.lock | 1 + app/assets/javascripts/application_legacy.js | 30 +- app/assets/javascripts/article-form.js | 605 + app/assets/javascripts/big.js | 1043 + app/assets/javascripts/delta_input.js | 9 +- app/assets/javascripts/group-order-form.js | 230 + app/assets/javascripts/migrate-units-form.js | 142 + app/assets/javascripts/receive-order-form.js | 159 + .../javascripts/unit-conversion-field.js | 275 + app/assets/javascripts/units-converter.js | 40 + app/assets/stylesheets/article.less | 38 + .../bootstrap_and_overrides.css.less | 179 +- app/assets/stylesheets/delta_input.less | 19 +- app/assets/stylesheets/group_order.less | 16 + app/assets/stylesheets/main.sass | 134 +- app/controllers/api/v1/articles_controller.rb | 61 + .../api/v1/order_articles_controller.rb | 2 +- .../user/group_order_articles_controller.rb | 2 +- app/controllers/article_units_controller.rb | 63 + app/controllers/articles_controller.rb | 295 +- app/controllers/deliveries_controller.rb | 2 +- .../finance/balancing_controller.rb | 10 +- .../group_order_articles_controller.rb | 2 +- app/controllers/order_articles_controller.rb | 39 +- app/controllers/orders_controller.rb | 12 +- app/controllers/stock_takings_controller.rb | 4 +- app/controllers/stockit_controller.rb | 69 +- app/controllers/supplier_shares_controller.rb | 17 + app/controllers/suppliers_controller.rb | 31 +- app/documents/order_by_articles.rb | 10 +- app/documents/order_by_groups.rb | 8 +- app/documents/order_fax.rb | 83 +- app/documents/order_matrix.rb | 18 +- app/helpers/application_helper.rb | 4 + app/helpers/articles_helper.rb | 128 +- app/helpers/deliveries_helper.rb | 4 +- app/helpers/group_order_articles_helper.rb | 19 +- app/helpers/group_orders_helper.rb | 8 +- app/helpers/orders_helper.rb | 104 +- app/helpers/suppliers_helper.rb | 10 +- app/inputs/delta_input.rb | 10 +- app/lib/articles_csv.rb | 67 +- app/lib/foodsoft_file.rb | 54 +- app/lib/order_csv.rb | 24 +- app/lib/order_pdf.rb | 48 +- app/lib/order_txt.rb | 63 +- app/models/article.rb | 230 +- app/models/article_price.rb | 31 - app/models/article_unit.rb | 43 + app/models/article_unit_ratio.rb | 6 + app/models/article_version.rb | 206 + app/models/concerns/price_calculation.rb | 60 + app/models/group_order.rb | 24 +- app/models/group_order_article.rb | 27 +- app/models/invoice.rb | 6 +- app/models/order.rb | 67 +- app/models/order_article.rb | 141 +- app/models/shared_article.rb | 30 - app/models/shared_supplier.rb | 36 - app/models/stock_article.rb | 6 +- app/models/supplier.rb | 183 +- app/serializers/article_unit_serializer.rb | 3 + app/serializers/order_article_serializer.rb | 4 +- .../article_units/_create_link.html.haml | 1 + .../article_units/_destroy_link.html.haml | 1 + app/views/article_units/_rows.html.haml | 16 + app/views/article_units/create.js.haml | 2 + app/views/article_units/destroy.js.haml | 2 + app/views/article_units/index.html.haml | 60 + app/views/article_units/search.js.haml | 1 + app/views/articles/_article.html.haml | 6 +- app/views/articles/_edit_all_table.html.haml | 69 +- app/views/articles/_form.html.haml | 23 +- .../articles/_import_article_added.js.erb | 4 - .../articles/_import_search_results.haml | 33 - app/views/articles/_sync.html.haml | 12 +- app/views/articles/_sync_table.html.haml | 78 +- app/views/articles/create.js.haml | 3 + app/views/articles/destroy.js.haml | 3 + app/views/articles/edit.html.haml | 2 + app/views/articles/edit_all.html.haml | 3 +- app/views/articles/index.html.haml | 22 +- app/views/articles/migrate_units.html.haml | 74 + app/views/articles/new.js.haml | 2 +- .../articles/prepare_units_migration.haml | 8 + app/views/articles/shared.js.haml | 1 - app/views/articles/update.js.haml | 2 +- app/views/articles/upload.html.haml | 77 +- .../_stock_article_for_adding.html.haml | 4 +- .../deliveries/_stock_change_fields.html.haml | 4 +- app/views/deliveries/add_stock_change.js.erb | 12 +- app/views/deliveries/show.html.haml | 2 +- .../balancing/_group_order_articles.html.haml | 5 +- .../balancing/_order_article.html.haml | 22 +- app/views/finance/balancing/new.html.haml | 11 +- app/views/finance/balancing/new.js.haml | 5 + .../new_on_order_article_create.js.erb | 14 +- .../new_on_order_article_update.js.erb | 10 +- .../group_order_articles/_form.html.haml | 4 +- app/views/group_orders/_form.html.haml | 103 +- app/views/group_orders/show.html.haml | 14 +- app/views/mailer/order_received.text.haml | 4 +- app/views/mailer/order_result.text.haml | 2 +- app/views/order_articles/_edit.html.haml | 21 +- app/views/order_articles/_new.html.haml | 2 +- app/views/order_articles/edit.js.haml | 4 +- app/views/order_articles/new.js.haml | 2 +- app/views/orders/_articles.html.haml | 26 +- app/views/orders/_edit_amount.html.haml | 22 +- app/views/orders/_edit_amounts.html.haml | 94 +- app/views/orders/_form.html.haml | 4 +- app/views/orders/add_article.js.erb | 6 +- .../receive_on_order_article_create.js.erb | 10 +- .../receive_on_order_article_update.js.erb | 34 +- app/views/orders/show.html.haml | 3 + app/views/orders/show.js.erb | 7 + .../shared/_article_fields_price.html.haml | 22 +- .../shared/_article_fields_units.html.haml | 37 +- app/views/shared/_article_unit_ratio.haml | 19 + ...l.haml => _article_version_info.html.haml} | 0 .../articles_by/_article_single.html.haml | 8 +- .../articles_by/_article_single_goa.html.haml | 3 +- .../shared/articles_by/_articles.html.haml | 2 +- .../articles_by/_group_single_goa.html.haml | 10 +- .../shared/articles_by/_groups.html.haml | 1 - .../_unit_conversion_popover_template.haml | 12 + .../stock_takings/_stock_change.html.haml | 2 +- app/views/stockit/_form.html.haml | 31 +- app/views/stockit/_stock_article.html.haml | 2 +- .../supplier_shares/_share_link.html.haml | 16 + app/views/supplier_shares/update.js.haml | 2 + app/views/suppliers/_form.html.haml | 8 +- .../suppliers/_import_search_results.haml | 29 + app/views/suppliers/index.html.haml | 2 - app/views/suppliers/remote_articles.js.haml | 22 + .../suppliers/shared_suppliers.html.haml | 25 - app/views/suppliers/show.html.haml | 7 +- bin/autospec | 4 +- bin/mailcatcher | 4 +- bin/resque | 4 +- bin/resque-web | 4 +- bin/rspec | 4 +- bin/yarn | 12 +- config/i18n-js.yml | 4 +- config/locales/de.yml | 117 +- config/locales/en.yml | 119 +- config/locales/es.yml | 19 +- config/locales/fr.yml | 17 +- config/locales/nl.yml | 19 +- config/locales/tr.yml | 31 +- config/navigation.rb | 5 +- config/puma.rb | 3 + config/routes.rb | 19 +- config/units-of-measure/locales/unece_de.yml | 763 + config/units-of-measure/locales/unece_en.yml | 761 + config/units-of-measure/locales/unece_es.yml | 733 + config/units-of-measure/locales/unece_fr.yml | 733 + config/units-of-measure/locales/unece_nl.yml | 733 + config/units-of-measure/locales/unece_tr.yml | 733 + .../units-of-measure/translations_piece.csv | 69 + .../translations_scalar-de.csv | 120 + .../translations_scalar-en.csv | 121 + .../units-of-measure/un-ece-20-remastered.yml | 22825 ++++++++++++++++ config/units-of-measure/un-ece-20.yml | 15383 +++++++++++ config/units-of-measure/un-ece-21.yml | 1202 + ...726083740_alter_articles_add_versioning.rb | 217 + ...3741_alter_articles_add_more_unit_logic.rb | 112 + ...26083742_alter_suppliers_sharing_fields.rb | 19 + .../20240726083743_create_article_units.rb | 37 + ...d_unit_migration_completed_to_suppliers.rb | 5 + db/schema.rb | 85 +- db/seeds.rb | 2 +- db/seeds/seed_helper.rb | 2 +- db/seeds/small.en.seeds.rb | 484 +- db/seeds/small.nl.seeds.rb | 322 - docker-compose-dev.yml | 2 + lib/article_units_lib.rb | 193 + lib/tasks/foodsoft.rake | 2 +- lib/tasks/temp_export_supplier.rake | 33 + lib/tasks/units.rake | 136 + .../current_orders/articles_controller.rb | 2 +- .../current_orders/group_orders_controller.rb | 2 +- .../current_orders/ordergroups_controller.rb | 7 +- .../documents/multiple_orders_by_articles.rb | 6 +- .../documents/multiple_orders_by_groups.rb | 12 +- .../articles/_article_info.html.haml | 18 +- .../articles/_articles.html.haml | 2 +- .../articles/_ordergroups.html.haml | 2 +- .../current_orders/articles/show.html.haml | 2 +- .../group_orders/_result.html.haml | 16 +- .../ordergroups/_article.html.haml | 6 +- .../ordergroups/_articles.html.haml | 2 +- .../supplier_shares_controller_spec.rb | 24 + spec/factories/article.rb | 59 +- spec/factories/article_category.rb | 7 + spec/factories/article_unit.rb | 7 + spec/factories/article_unit_ratio.rb | 10 + spec/factories/article_version.rb | 43 + spec/factories/supplier.rb | 7 +- spec/fixtures/foodsoft_file_01.csv | 10 +- spec/fixtures/foodsoft_file_01.ods | Bin 21727 -> 4388 bytes spec/fixtures/foodsoft_file_01.xls | Bin 15872 -> 27648 bytes spec/fixtures/foodsoft_file_01.xlsx | Bin 5621 -> 10154 bytes spec/fixtures/foodsoft_file_02.csv | 4 +- spec/helpers/articles_helper_spec.rb | 125 + spec/integration/article_units_spec.rb | 64 + spec/integration/articles_spec.rb | 155 +- spec/integration/balancing_spec.rb | 8 +- spec/integration/order_spec.rb | 2 +- .../product_distribution_example_spec.rb | 13 +- spec/integration/receive_spec.rb | 12 +- spec/lib/article_units_lib_spec.rb | 136 + spec/lib/order_txt_csv_spec.rb | 49 + spec/models/article_spec.rb | 145 +- spec/models/article_version_spec.rb | 225 + spec/models/group_order_article_spec.rb | 4 +- spec/models/order_article_spec.rb | 57 +- spec/models/supplier_spec.rb | 79 - .../articles_controller_spec.rb | 141 + spec/support/active_record_helper.rb | 19 + spec/support/shared_database.rb | 20 - spec/support/spec_test_helper.rb | 16 +- spec/swagger_helper.rb | 144 +- 225 files changed, 52371 insertions(+), 2249 deletions(-) create mode 100644 .eslintrc.js create mode 100644 app/assets/javascripts/article-form.js create mode 100644 app/assets/javascripts/big.js create mode 100644 app/assets/javascripts/group-order-form.js create mode 100644 app/assets/javascripts/migrate-units-form.js create mode 100644 app/assets/javascripts/receive-order-form.js create mode 100644 app/assets/javascripts/unit-conversion-field.js create mode 100644 app/assets/javascripts/units-converter.js create mode 100644 app/assets/stylesheets/article.less create mode 100644 app/assets/stylesheets/group_order.less create mode 100644 app/controllers/api/v1/articles_controller.rb create mode 100644 app/controllers/article_units_controller.rb create mode 100644 app/controllers/supplier_shares_controller.rb delete mode 100644 app/models/article_price.rb create mode 100644 app/models/article_unit.rb create mode 100644 app/models/article_unit_ratio.rb create mode 100644 app/models/article_version.rb delete mode 100644 app/models/shared_article.rb delete mode 100644 app/models/shared_supplier.rb create mode 100644 app/serializers/article_unit_serializer.rb create mode 100644 app/views/article_units/_create_link.html.haml create mode 100644 app/views/article_units/_destroy_link.html.haml create mode 100644 app/views/article_units/_rows.html.haml create mode 100644 app/views/article_units/create.js.haml create mode 100644 app/views/article_units/destroy.js.haml create mode 100644 app/views/article_units/index.html.haml create mode 100644 app/views/article_units/search.js.haml delete mode 100644 app/views/articles/_import_article_added.js.erb delete mode 100644 app/views/articles/_import_search_results.haml create mode 100644 app/views/articles/edit.html.haml create mode 100644 app/views/articles/migrate_units.html.haml create mode 100644 app/views/articles/prepare_units_migration.haml delete mode 100644 app/views/articles/shared.js.haml create mode 100644 app/views/shared/_article_unit_ratio.haml rename app/views/shared/{_article_price_info.html.haml => _article_version_info.html.haml} (100%) create mode 100644 app/views/shared/js_templates/_unit_conversion_popover_template.haml create mode 100644 app/views/supplier_shares/_share_link.html.haml create mode 100644 app/views/supplier_shares/update.js.haml create mode 100644 app/views/suppliers/_import_search_results.haml create mode 100644 app/views/suppliers/remote_articles.js.haml delete mode 100644 app/views/suppliers/shared_suppliers.html.haml create mode 100644 config/units-of-measure/locales/unece_de.yml create mode 100644 config/units-of-measure/locales/unece_en.yml create mode 100644 config/units-of-measure/locales/unece_es.yml create mode 100644 config/units-of-measure/locales/unece_fr.yml create mode 100644 config/units-of-measure/locales/unece_nl.yml create mode 100644 config/units-of-measure/locales/unece_tr.yml create mode 100644 config/units-of-measure/translations_piece.csv create mode 100644 config/units-of-measure/translations_scalar-de.csv create mode 100644 config/units-of-measure/translations_scalar-en.csv create mode 100644 config/units-of-measure/un-ece-20-remastered.yml create mode 100644 config/units-of-measure/un-ece-20.yml create mode 100644 config/units-of-measure/un-ece-21.yml create mode 100644 db/migrate/20240726083740_alter_articles_add_versioning.rb create mode 100644 db/migrate/20240726083741_alter_articles_add_more_unit_logic.rb create mode 100644 db/migrate/20240726083742_alter_suppliers_sharing_fields.rb create mode 100644 db/migrate/20240726083743_create_article_units.rb create mode 100644 db/migrate/20240726083744_add_unit_migration_completed_to_suppliers.rb delete mode 100644 db/seeds/small.nl.seeds.rb create mode 100644 lib/article_units_lib.rb create mode 100644 lib/tasks/temp_export_supplier.rake create mode 100644 lib/tasks/units.rake create mode 100644 spec/controllers/supplier_shares_controller_spec.rb create mode 100644 spec/factories/article_category.rb create mode 100644 spec/factories/article_unit.rb create mode 100644 spec/factories/article_unit_ratio.rb create mode 100644 spec/factories/article_version.rb create mode 100644 spec/helpers/articles_helper_spec.rb create mode 100644 spec/integration/article_units_spec.rb create mode 100644 spec/lib/article_units_lib_spec.rb create mode 100644 spec/lib/order_txt_csv_spec.rb create mode 100644 spec/models/article_version_spec.rb create mode 100644 spec/requests/api/v1/shared_suppliers/articles_controller_spec.rb create mode 100644 spec/support/active_record_helper.rb delete mode 100644 spec/support/shared_database.rb diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..e1dce34a6 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + "env": { + "browser": true, + "jquery": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 6 + }, + "rules": { + "no-unused-vars": ["error", { "vars": "local" }] + } +} diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 894d0e0b5..c8b48e1b0 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2024-01-26 16:46:38 UTC using RuboCop version 1.60.2. +# on 2024-05-24 07:29:47 UTC using RuboCop version 1.60.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -47,6 +47,14 @@ FactoryBot/FactoryAssociationWithStrategy: - 'spec/factories/invoice.rb' - 'spec/factories/order.rb' +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Include. +# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb +FactoryBot/SyntaxMethods: + Exclude: + - 'spec/models/article_spec.rb' + # Offense count: 2 # Configuration parameters: EnforcedStyle, AllowedGems, Include. # SupportedStyles: Gemfile, gems.rb, gemspec @@ -71,12 +79,49 @@ Gemspec/RequiredRubyVersion: - 'plugins/uservoice/foodsoft_uservoice.gemspec' - 'plugins/wiki/foodsoft_wiki.gemspec' -# Offense count: 41 +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: with_first_argument, with_fixed_indentation +Layout/ArgumentAlignment: + Exclude: + - 'app/controllers/stockit_controller.rb' + - 'app/documents/order_by_articles.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Layout/EmptyLines: + Exclude: + - 'app/models/invoice.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'app/controllers/stockit_controller.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Width, AllowedPatterns. +Layout/IndentationWidth: + Exclude: + - 'app/models/article.rb' + +# Offense count: 42 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowSafeAssignment. Lint/AssignmentInCondition: Enabled: false +# Offense count: 1 +Lint/BinaryOperatorWithIdenticalOperands: + Exclude: + - 'app/helpers/orders_helper.rb' + # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). Lint/BooleanSymbol: @@ -91,10 +136,9 @@ Lint/DuplicateBranch: - 'app/controllers/orders_controller.rb' - 'plugins/wiki/app/controllers/pages_controller.rb' -# Offense count: 3 +# Offense count: 2 Lint/DuplicateMethods: Exclude: - - 'app/models/invoice.rb' - 'plugins/messages/app/models/message.rb' # Offense count: 2 @@ -110,6 +154,11 @@ Lint/EnsureReturn: Exclude: - 'app/controllers/finance/bank_accounts_controller.rb' +# Offense count: 1 +Lint/FloatComparison: + Exclude: + - 'lib/article_units_lib.rb' + # Offense count: 1 Lint/IneffectiveAccessModifier: Exclude: @@ -121,6 +170,12 @@ Lint/Loop: Exclude: - 'app/models/concerns/mark_as_deleted_with_name.rb' +# Offense count: 1 +# Configuration parameters: MaximumRangeSize. +Lint/MissingCopEnableDirective: + Exclude: + - 'config/routes.rb' + # Offense count: 2 Lint/MixedRegexpCaptureTypes: Exclude: @@ -172,7 +227,7 @@ Lint/UnderscorePrefixedVariableName: Exclude: - 'app/models/order_article.rb' -# Offense count: 14 +# Offense count: 16 # This cop supports unsafe autocorrection (--autocorrect-all). Lint/UselessAssignment: Exclude: @@ -188,34 +243,35 @@ Lint/UselessAssignment: - 'plugins/current_orders/app/documents/multiple_orders_by_articles.rb' - 'plugins/current_orders/app/documents/multiple_orders_by_groups.rb' - 'spec/lib/foodsoft_config_spec.rb' + - 'spec/models/article_spec.rb' -# Offense count: 163 +# Offense count: 186 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: - Max: 143 + Max: 145 -# Offense count: 12 +# Offense count: 21 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. # AllowedMethods: refine Metrics/BlockLength: - Max: 60 + Max: 80 -# Offense count: 2 +# Offense count: 5 # Configuration parameters: CountBlocks. Metrics/BlockNesting: Max: 4 -# Offense count: 18 +# Offense count: 22 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 304 + Max: 350 -# Offense count: 51 +# Offense count: 63 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: - Max: 20 + Max: 22 -# Offense count: 164 +# Offense count: 192 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: Max: 115 @@ -223,17 +279,17 @@ Metrics/MethodLength: # Offense count: 4 # Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: - Max: 192 + Max: 195 # Offense count: 1 # Configuration parameters: CountKeywordArgs, MaxOptionalParameters. Metrics/ParameterLists: Max: 6 -# Offense count: 36 +# Offense count: 48 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: - Max: 21 + Max: 23 # Offense count: 6 Naming/AccessorMethodName: @@ -257,7 +313,7 @@ Naming/MemoizedInstanceVariableName: Exclude: - 'plugins/messages/app/models/message.rb' -# Offense count: 16 +# Offense count: 15 # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to Naming/MethodParameterName: @@ -270,7 +326,6 @@ Naming/MethodParameterName: - 'spec/integration/config_spec.rb' - 'spec/integration/receive_spec.rb' - 'spec/models/order_article_spec.rb' - - 'spec/support/shared_database.rb' # Offense count: 11 # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. @@ -317,6 +372,7 @@ RSpec/BeforeAfterAll: # Configuration parameters: EnabledMethods. RSpec/Capybara/FeatureMethods: Exclude: + - 'spec/integration/article_units_spec.rb' - 'spec/integration/articles_spec.rb' - 'spec/integration/balancing_spec.rb' - 'spec/integration/config_spec.rb' @@ -328,7 +384,7 @@ RSpec/Capybara/FeatureMethods: - 'spec/integration/session_spec.rb' - 'spec/integration/supplier_spec.rb' -# Offense count: 12 +# Offense count: 11 # Configuration parameters: Prefixes, AllowedPatterns. # Prefixes: when, with, without RSpec/ContextWording: @@ -357,6 +413,7 @@ RSpec/DescribedClass: RSpec/EmptyExampleGroup: Exclude: - 'spec/requests/api/v1/article_categories_controller_spec.rb' + - 'spec/requests/api/v1/shared_suppliers/articles_controller_spec.rb' - 'spec/requests/api/v1/configs_controller_spec.rb' - 'spec/requests/api/v1/financial_transaction_classes_controller_spec.rb' - 'spec/requests/api/v1/financial_transaction_types_controller_spec.rb' @@ -368,7 +425,7 @@ RSpec/EmptyExampleGroup: - 'spec/requests/api/v1/user/group_order_articles_spec.rb' - 'spec/requests/api/v1/user/users_spec.rb' -# Offense count: 69 +# Offense count: 83 # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 81 @@ -378,6 +435,7 @@ RSpec/ExampleLength: # Include: **/*_spec*rb*, **/spec/**/* RSpec/FilePath: Exclude: + - 'spec/integration/article_units_spec.rb' - 'spec/integration/articles_spec.rb' - 'spec/integration/login_spec.rb' - 'spec/lib/bank_account_information_importer_spec.rb' @@ -405,12 +463,11 @@ RSpec/IteratedExpectation: - 'spec/models/order_spec.rb' - 'spec/models/supplier_spec.rb' -# Offense count: 3 +# Offense count: 2 RSpec/LetSetup: Exclude: - 'spec/models/bank_transaction_spec.rb' - 'spec/models/group_order_article_spec.rb' - - 'spec/models/supplier_spec.rb' # Offense count: 3 RSpec/MissingExampleGroupArgument: @@ -419,7 +476,7 @@ RSpec/MissingExampleGroupArgument: - 'spec/models/group_order_spec.rb' - 'spec/models/user_spec.rb' -# Offense count: 103 +# Offense count: 101 RSpec/MultipleExpectations: Max: 22 @@ -433,13 +490,12 @@ RSpec/MultipleMemoizedHelpers: RSpec/NestedGroups: Max: 4 -# Offense count: 8 +# Offense count: 6 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers. # SupportedStyles: inflected, explicit RSpec/PredicateMatcher: Exclude: - - 'spec/models/article_spec.rb' - 'spec/models/user_spec.rb' # Offense count: 7 @@ -471,6 +527,7 @@ RSpec/RepeatedExample: # Include: **/*_spec.rb RSpec/SpecFilePathFormat: Exclude: + - 'spec/integration/article_units_spec.rb' - 'spec/integration/articles_spec.rb' - 'spec/integration/login_spec.rb' - 'spec/lib/bank_account_information_importer_spec.rb' @@ -507,7 +564,7 @@ Rails/ApplicationRecord: - 'plugins/printer/app/models/printer_job.rb' - 'plugins/printer/app/models/printer_job_update.rb' -# Offense count: 12 +# Offense count: 32 # Configuration parameters: Database, Include. # SupportedDatabases: mysql, postgresql # Include: db/**/*.rb @@ -523,8 +580,18 @@ Rails/BulkChangeTable: - 'db/migrate/20171201000000_add_name_short_to_financial_transaction_type.rb' - 'db/migrate/20181201000100_create_message_recipients.foodsoft_messages.rb' - 'db/migrate/20181201000200_add_deleted_to_financial_transaction_type.rb' + - 'db/migrate/20230915093041_add_payment_to_financial_transaction.rb' + - 'db/migrate/20240316190956_alter_articles_add_versioning.rb' + - 'db/migrate/20240316190957_alter_articles_add_more_unit_logic.rb' + - 'db/migrate/20240316190958_alter_suppliers_sharing_fields.rb' -# Offense count: 34 +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Rails/CompactBlank: + Exclude: + - 'app/controllers/orders_controller.rb' + +# Offense count: 35 # Configuration parameters: Include. # Include: db/**/*.rb Rails/CreateTableWithTimestamps: @@ -542,7 +609,7 @@ Rails/Date: - 'spec/integration/order_spec.rb' - 'spec/models/order_spec.rb' -# Offense count: 68 +# Offense count: 74 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: Whitelist, AllowedMethods, AllowedReceivers. # Whitelist: find_by_sql, find_by_token_for @@ -551,7 +618,7 @@ Rails/Date: Rails/DynamicFindBy: Enabled: false -# Offense count: 16 +# Offense count: 17 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowedMethods, AllowedPatterns. # AllowedMethods: order, limit, select, lock @@ -559,6 +626,7 @@ Rails/FindEach: Exclude: - 'app/lib/financial_transactions_csv.rb' - 'app/lib/order_txt.rb' + - 'app/models/order.rb' - 'db/migrate/20090120184410_road_to_version_three.rb' - 'db/migrate/20090731132547_add_stats_to_groups.rb' - 'db/migrate/20130622095040_move_weekly_tasks.rb' @@ -568,20 +636,19 @@ Rails/FindEach: - 'db/seeds/seed_helper.rb' - 'lib/tasks/foodsoft.rake' -# Offense count: 26 +# Offense count: 24 # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/HasManyOrHasOneDependent: Exclude: - 'app/models/article.rb' - 'app/models/article_category.rb' - - 'app/models/article_price.rb' + - 'app/models/article_version.rb' - 'app/models/financial_link.rb' - 'app/models/financial_transaction.rb' - 'app/models/group_order.rb' - 'app/models/order.rb' - 'app/models/ordergroup.rb' - - 'app/models/shared_supplier.rb' - 'app/models/stock_article.rb' - 'app/models/supplier.rb' - 'app/models/supplier_category.rb' @@ -597,7 +664,7 @@ Rails/HelperInstanceVariable: - 'app/helpers/application_helper.rb' - 'app/helpers/orders_helper.rb' -# Offense count: 22 +# Offense count: 20 # Configuration parameters: IgnoreScopes, Include. # Include: app/models/**/*.rb Rails/InverseOf: @@ -609,8 +676,6 @@ Rails/InverseOf: - 'app/models/invoice.rb' - 'app/models/mail_delivery_status.rb' - 'app/models/order.rb' - - 'app/models/shared_article.rb' - - 'app/models/shared_supplier.rb' - 'app/models/stock_change.rb' - 'app/models/supplier.rb' - 'app/models/task.rb' @@ -625,12 +690,11 @@ Rails/LexicallyScopedActionFilter: - 'app/controllers/group_orders_controller.rb' - 'app/controllers/suppliers_controller.rb' -# Offense count: 3 +# Offense count: 2 # This cop supports unsafe autocorrection (--autocorrect-all). Rails/NegateInclude: Exclude: - 'app/helpers/application_helper.rb' - - 'app/models/supplier.rb' - 'lib/tasks/foodsoft_setup.rake' # Offense count: 34 @@ -664,6 +728,12 @@ Rails/OutputSafety: - 'plugins/messages/app/helpers/messages_helper.rb' - 'plugins/wiki/app/helpers/pages_helper.rb' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Rails/Pluck: + Exclude: + - 'app/controllers/articles_controller.rb' + # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. @@ -694,7 +764,7 @@ Rails/RedundantActiveRecordAllMethod: # This cop supports unsafe autocorrection (--autocorrect-all). Rails/RedundantPresenceValidationOnBelongsTo: Exclude: - - 'app/models/article.rb' + - 'app/models/article_version.rb' - 'app/models/bank_transaction.rb' - 'app/models/delivery.rb' - 'app/models/financial_transaction.rb' @@ -720,7 +790,7 @@ Rails/SelectMap: Exclude: - 'app/lib/foodsoft/expansion_variables.rb' -# Offense count: 64 +# Offense count: 72 # Configuration parameters: ForbiddenMethods, AllowedMethods. # ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all Rails/SkipsModelValidations: @@ -747,7 +817,7 @@ Rails/ThreeStateBooleanColumn: - 'db/migrate/20130624084223_remove_weekly_from_tasks.rb' - 'db/migrate/20130624085246_remove_weekly_task_from_groups.rb' -# Offense count: 42 +# Offense count: 48 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: strict, flexible @@ -821,7 +891,7 @@ Style/CaseEquality: Exclude: - 'lib/tasks/foodsoft_setup.rake' -# Offense count: 55 +# Offense count: 57 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: nested, compact @@ -845,7 +915,7 @@ Style/CommentedKeyword: - 'config/routes.rb' - 'db/migrate/20090120184410_road_to_version_three.rb' -# Offense count: 338 +# Offense count: 353 # Configuration parameters: AllowedConstants. Style/Documentation: Enabled: false @@ -866,7 +936,7 @@ Style/FloatDivision: Exclude: - 'app/models/ordergroup.rb' -# Offense count: 18 +# Offense count: 17 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: each, for @@ -877,7 +947,6 @@ Style/For: - 'app/models/group_order.rb' - 'app/models/order.rb' - 'app/models/stock_taking.rb' - - 'app/models/supplier.rb' - 'db/migrate/005_create_financial_transactions.rb' - 'lib/tasks/foodsoft.rake' - 'plugins/messages/app/mail_receivers/messages_mail_receiver.rb' @@ -891,7 +960,7 @@ Style/For: Style/FormatStringToken: EnforcedStyle: unannotated -# Offense count: 514 +# Offense count: 546 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: always, always_true, never @@ -913,21 +982,16 @@ Style/GuardClause: Exclude: - 'plugins/wiki/app/controllers/pages_controller.rb' -# Offense count: 2 +# Offense count: 3 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowedReceivers. # AllowedReceivers: Thread.current Style/HashEachMethods: Exclude: + - 'app/controllers/articles_controller.rb' - 'app/models/group_order.rb' - 'spec/integration/config_spec.rb' -# Offense count: 2 -# This cop supports unsafe autocorrection (--autocorrect-all). -Style/HashExcept: - Exclude: - - 'spec/models/article_spec.rb' - # Offense count: 8 # Configuration parameters: MinBranchesCount. Style/HashLikeCase: @@ -949,6 +1013,12 @@ Style/IfWithBooleanLiteralBranches: Exclude: - 'app/models/order_article.rb' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/InfiniteLoop: + Exclude: + - 'app/lib/order_pdf.rb' + # Offense count: 3 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: InverseMethods, InverseBlocks. @@ -969,7 +1039,13 @@ Style/LineEndConcatenation: # This cop supports unsafe autocorrection (--autocorrect-all). Style/MapToHash: Exclude: - - 'app/models/article.rb' + - 'app/models/article_version.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/MinMaxComparison: + Exclude: + - 'app/models/group_order_article.rb' # Offense count: 1 Style/MixinUsage: @@ -982,45 +1058,43 @@ Style/MultilineBlockChain: - 'app/helpers/group_orders_helper.rb' - 'app/models/order.rb' -# Offense count: 24 +# Offense count: 25 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: literals, strict Style/MutableConstant: Enabled: false -# Offense count: 60 +# Offense count: 64 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. # SupportedStyles: predicate, comparison Style/NumericPredicate: Enabled: false -# Offense count: 5 +# Offense count: 1 +Style/OpenStructUse: + Exclude: + - 'app/controllers/suppliers_controller.rb' + +# Offense count: 6 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - 'app/helpers/application_helper.rb' + - 'app/helpers/group_order_articles_helper.rb' - 'app/helpers/orders_helper.rb' - 'app/models/order_article.rb' - 'lib/tasks/foodsoft_setup.rake' -# Offense count: 2 +# Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. # SupportedStyles: short, verbose Style/PreferredHashMethods: Exclude: - 'app/helpers/admin/configs_helper.rb' - - 'app/helpers/articles_helper.rb' - -# Offense count: 1 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: Methods. -Style/RedundantArgument: - Exclude: - - 'app/controllers/articles_controller.rb' # Offense count: 3 # This cop supports unsafe autocorrection (--autocorrect-all). @@ -1052,7 +1126,7 @@ Style/ReturnNilInPredicateMethodDefinition: - 'app/controllers/group_orders_controller.rb' - 'app/models/article.rb' -# Offense count: 9 +# Offense count: 11 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. # AllowedMethods: present?, blank?, presence, try, try! @@ -1060,6 +1134,7 @@ Style/SafeNavigation: Exclude: - 'app/controllers/concerns/auth_api.rb' - 'app/controllers/group_order_articles_controller.rb' + - 'app/models/article.rb' - 'app/models/article_category.rb' - 'app/models/bank_account.rb' - 'app/models/financial_transaction.rb' @@ -1067,27 +1142,28 @@ Style/SafeNavigation: - 'plugins/printer/app/controllers/printer_controller.rb' - 'spec/factories/order.rb' -# Offense count: 4 +# Offense count: 5 # This cop supports unsafe autocorrection (--autocorrect-all). Style/SlicingWithRange: Exclude: - 'app/helpers/admin/configs_helper.rb' + - 'app/lib/order_pdf.rb' - 'config/initializers/session_store.rb' -# Offense count: 9 +# Offense count: 10 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: RequireEnglish. # SupportedStyles: use_perl_names, use_english_names, use_builtin_english_names Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 35 +# Offense count: 37 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: Mode. Style/StringConcatenation: Enabled: false -# Offense count: 20 +# Offense count: 19 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. # AllowedMethods: define_method, mail, respond_to @@ -1114,7 +1190,7 @@ Style/ZeroLengthPredicate: - 'plugins/current_orders/app/documents/multiple_orders_by_articles.rb' - 'plugins/current_orders/app/documents/multiple_orders_by_groups.rb' -# Offense count: 270 +# Offense count: 436 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. # URISchemes: http, https diff --git a/Gemfile.lock b/Gemfile.lock index 355e55eaa..adf9f9a1d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -624,6 +624,7 @@ GEM zeitwerk (2.6.12) PLATFORMS + ruby x86_64-linux DEPENDENCIES diff --git a/app/assets/javascripts/application_legacy.js b/app/assets/javascripts/application_legacy.js index cd4a7273a..80c5a8129 100644 --- a/app/assets/javascripts/application_legacy.js +++ b/app/assets/javascripts/application_legacy.js @@ -16,7 +16,13 @@ //= require i18n //= require i18n/translations //= require_self -//= require ordering +//= require big +//= require units-converter +//= require migrate-units-form +//= require article-form +//= require unit-conversion-field +//= require group-order-form +//= require receive-order-form //= require stupidtable //= require touchclick //= require delta_input @@ -24,6 +30,18 @@ $.fn.select2.defaults.set('theme', 'bootstrap'); +// on first focus (bubbles up to document), open the menu +$(document).on('focus', '.select2-selection.select2-selection--single', function () { + $(this).closest(".select2-container").siblings('select:enabled').select2('open'); +}); + +// steal focus during close - only capture once and stop propogation +$('select.select2').on('select2:closing', function (e) { + $(e.target).data("select2").$selection.one('focus focusin', function (e) { + e.stopPropagation(); + }); +}); + // Load following statements, when DOM is ready $(function() { @@ -81,7 +99,7 @@ $(function() { // Submission will be done after 500ms of not typed, unless data-submit-onchange=changed, // in which case it happens when the input box loses its focus ('changed' event). // (changeDate is for bootstrap-datepicker) - $(document).on('changed keyup focusin changeDate', 'form[data-submit-onchange] input[type=text]:not([data-ignore-onchange])', function(e) { + $(document).on('changed keyup focusin changeDate', 'form[data-submit-onchange] input[type=number]:not([data-ignore-onchange])', function(e) { var input = $(this); // when form has data-submit-onchange=changed, don't do updates while typing if (e.type!='changed' && e.type!='changeDate' && input.parents('form[data-submit-onchange=changed]').length>0) { @@ -95,6 +113,10 @@ $(function() { // trigger timeout to submit form when value was changed clearTimeout(input.data('submit-timeout-id')); input.data('submit-timeout-id', setTimeout(function() { + if (input.data('multiply-before-submit')) { + input.parents('form').find(`input[type="hidden"][name="${input.attr('name')}"]`).remove(); + input.parents('form').append(``); + } if (input.val() != input.data('old-value')) input.parents('form').submit(); input.removeData('submit-timeout-id'); input.removeData('old-value'); @@ -122,6 +144,10 @@ $(function() { // Handle ajax errors // render json: {error: "can't except this!"}, status: :unprocessable_entity $(document).ajaxError(function(ev, xhr, settings, exception) { + if (xhr.statusText === 'abort') { + return; + } + try { msg = xhr.responseJSON.error; } catch(err) { diff --git a/app/assets/javascripts/article-form.js b/app/assets/javascripts/article-form.js new file mode 100644 index 000000000..c7c9f4223 --- /dev/null +++ b/app/assets/javascripts/article-form.js @@ -0,0 +1,605 @@ +class ArticleForm { + constructor(articleUnitRatioTemplate$, articleForm$, units, priceMarkup, multiForm$, unitFieldsIdPrefix, unitFieldsNamePrefix) { + try { + this.units = units; + this.priceMarkup = priceMarkup; + this.unitFieldsIdPrefix = unitFieldsIdPrefix === undefined ? 'article_version' : unitFieldsIdPrefix; + this.unitFieldsNamePrefix = unitFieldsNamePrefix === undefined ? this.unitFieldsIdPrefix : unitFieldsNamePrefix; + this.articleUnitRatioTemplate$ = articleUnitRatioTemplate$; + this.articleForm$ = articleForm$; + this.unitConversionPopoverTemplate$ = $('#unit_conversion_popover_content_template'); + this.unit$ = $(`#${this.unitFieldsIdPrefix}_unit`, this.articleForm$); + this.customUnitWarning$ = $('.icon-warning-sign', this.articleForm$); + this.supplierUnitSelect$ = $(`#${this.unitFieldsIdPrefix}_supplier_order_unit`, this.articleForm$); + this.unitRatiosTable$ = $('#fc_base_price', this.articleForm$); + this.minimumOrderQuantity$ = $(`#${this.unitFieldsIdPrefix}_minimum_order_quantity`, this.articleForm$); + this.billingUnit$ = $(`#${this.unitFieldsIdPrefix}_billing_unit`, this.articleForm$); + this.groupOrderGranularity$ = $(`#${this.unitFieldsIdPrefix}_group_order_granularity`, this.articleForm$); + this.groupOrderUnit$ = $(`#${this.unitFieldsIdPrefix}_group_order_unit`, this.articleForm$); + this.price$ = $(`#${this.unitFieldsIdPrefix}_price`, this.articleForm$); + this.priceUnit$ = $(`#${this.unitFieldsIdPrefix}_price_unit`, this.articleForm$); + this.tax$ = $(`#${this.unitFieldsIdPrefix}_tax`, this.articleForm$); + this.deposit$ = $(`#${this.unitFieldsIdPrefix}_deposit`, this.articleForm$); + this.fcPrice$ = $(`#article_fc_price`, this.articleForm$); + this.unitsToOrder$ = $('#order_article_units_to_order', this.articleForm$); + this.unitsReceived$ = $('#order_article_units_received', this.articleForm$); + this.toggleExtraUnitsButton$ = $('.toggle-extra-units', this.articleForm$); + this.extraUnits$ = $('.extra-unit-fields', this.articleForm$); + this.submitButton$ = $('input[type="submit"]', this.articleForm$); + this.multiForm$ = multiForm$; + const selectContainer$ = this.articleForm$.parents('#modalContainer'); + this.select2Config = { + dropdownParent: selectContainer$.length === 0 ? undefined : selectContainer$ + }; + + this.loadAvailableUnits(); + this.initializeRegularFormFields(); + + this.initializeRatioRows(); + this.bindAddRatioButton(); + + this.setFieldVisibility(); + + this.loadRatios(); + this.prepareRatioDataForSequentialRepresentation(); + this.convertPriceToPriceUnit(); + this.initializePriceDisplay(); + this.initializeOrderedAndReceivedUnits(); + this.convertOrderedAndReceivedUnits(this.supplierUnitSelect$.val(), this.billingUnit$.val()); + this.initializeFormSubmitListener(); + this.initializeToggleExtraUnitsButton(); + this.enableSubmitButton(); + } catch (e) { + console.log('Could not initialize article form', e, 'articleUnitRatioTemplate$', articleUnitRatioTemplate$, 'articleForm$', articleForm$, 'units', units, 'priceMarkup', priceMarkup, 'multiForm$', multiForm$, 'unitFieldsIdPrefix', unitFieldsIdPrefix, 'unitFieldsNamePrefix', unitFieldsNamePrefix); + } + } + + initializePriceDisplay() { + mergeJQueryObjects([this.price$, this.priceUnit$, this.tax$, this.deposit$]).on('change keyup', () => { + const price = parseFloat(this.price$.val()); + const tax = parseFloat(this.tax$.val()); + const deposit = parseFloat(this.deposit$.val()); + const grossPrice = (price + deposit) * (tax / 100 + 1); + const fcPrice = grossPrice * (this.priceMarkup / 100 + 1); + const priceUnitLabel = this.getUnitLabel(this.priceUnit$.val()); + this.fcPrice$.find('.price_value').text(isNaN(fcPrice) ? '?' : I18n.l('currency', fcPrice)); + this.fcPrice$.find('.price_per_text').toggle(priceUnitLabel.trim() !== ''); + this.fcPrice$.find('.price_unit').text(priceUnitLabel); + }); + + this.price$.trigger('change'); + } + + getUnitLabel(unitKey) { + if (unitKey === '') { + return this.unit$.val(); + } + const unit = this.availableUnits.find((availableUnit) => availableUnit.key === unitKey); + if (unit === undefined) { + return '?'; + } + return unit.symbol != null ? unit.symbol : unit.label; + } + + initializeFormSubmitListener() { + (this.multiForm$ === undefined ? this.articleForm$ : this.multiForm$).submit((e) => { + try { + this.undoSequentialRatioDataRepresentation(); + this.loadRatios(); + this.undoPriceConversion(); + this.undoOrderAndReceivedUnitsConversion(); + } catch(err) { + e.preventDefault(); + throw err; + } + }); + } + + initializeToggleExtraUnitsButton() { + if (this.toggleExtraUnitsButton$.length > 0) { + this.setExtraUnitsButtonStatus(); + + this.toggleExtraUnitsButton$.on('click', (e) => { + this.toggleExtraUnits(); + }); + + this.supplierUnitSelect$.on('change', () => this.setExtraUnitsButtonStatus()); + } + } + + setExtraUnitsButtonStatus() { + if (this.hasDeviatingExtraUnits()) { + this.toggleExtraUnitsButton$.removeClass('default-values'); + } else { + this.toggleExtraUnitsButton$.addClass('default-values'); + } + } + + hasDeviatingExtraUnits() { + if ($(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[quantity]"]`).length > 0) { + return true; + } + + const supplierOrderUnit = this.supplierUnitSelect$.val(); + if (supplierOrderUnit !== this.groupOrderUnit$.val() || supplierOrderUnit !== this.billingUnit$.val()) { + return true; + } + + if (this.minimumOrderQuantity$.val().trim() !== '' || parseFloat(this.groupOrderGranularity$.val().trim()) !== 1) { + return true; + } + + return false; + } + + toggleExtraUnits() { + this.setExtraUnitsButtonStatus(); + $(document).off('mousedown.extra-units'); + this.extraUnits$.toggleClass('show'); + this.toggleExtraUnitsButton$.toggleClass('show'); + + if (this.extraUnits$.hasClass('show')) { + $(document).on('mousedown.extra-units', (e) => { + if ($(e.target).parents(this.extraUnits$.selector).length !== 0 || e.target === this.extraUnits$[0] || e.target === this.toggleExtraUnitsButton$[0]) { + return; + } + + this.toggleExtraUnits(); + }); + } + } + + getUnitsConverter() { + return new UnitsConverter(this.units, this.ratios, this.supplierUnitSelect$.val()); + } + + getUnitRatio(quantity, inputUnit, outputUnit) { + const converter = this.getUnitsConverter(); + return converter.getUnitRatio(quantity, inputUnit, outputUnit); + } + + undoPriceConversion() { + const relativePrice = this.price$.val(); + const priceUnit = this.priceUnit$.val(); + if (priceUnit === undefined) { + return; + } + const ratio = this.getUnitRatio(1, priceUnit, this.supplierUnitSelect$.val()); + const supplierUnitPrice = relativePrice / ratio; + const hiddenPriceField$ = $(``); + this.articleForm$.append(hiddenPriceField$); + } + + undoOrderAndReceivedUnitsConversion() { + this.convertOrderedAndReceivedUnits(this.billingUnit$.val(), this.supplierUnitSelect$.val()); + } + + loadAvailableUnits() { + this.availableUnits = Object.entries(this.units) + .filter(([, unit]) => unit.visible) + .map(([code, unit]) => { + let label = unit.name; + if (unit.symbol != null) { + label += ` (${unit.symbol})`; + } + return { key: code, label, baseUnit: unit.baseUnit, symbol: unit.symbol, aliases: unit.aliases ? unit.aliases : [] }; + }); + + $(`#${this.unitFieldsIdPrefix}_supplier_order_unit`, this.articleForm$).select2(this.select2Config); + } + + initializeRegularFormFields() { + this.unit$.change(() => { + this.setMinimumOrderUnitDisplay(); + this.updateAvailableBillingAndGroupOrderUnits(); + this.updateUnitMultiplierLabels(); + this.updateCustomUnitWarning(); + }); + this.updateCustomUnitWarning(); + this.unit$.keyup(() => this.unit$.trigger('change')); + + + this.supplierUnitSelect$.change(() => { + this.onSupplierUnitChanged(); + this.updateCustomUnitWarning(); + }); + this.onSupplierUnitChanged(); + } + + updateCustomUnitWarning() { + const supplierUnitValueChosen = this.supplierUnitSelect$.val() !== undefined && this.supplierUnitSelect$.val().trim() !== ''; + if (supplierUnitValueChosen) { + this.customUnitWarning$.hide(); + return; + } + + const unitVal = this.unit$.val().trim().toLowerCase(); + if (unitVal !== '' && (unitVal.match(/[0-9]/) || this.availableUnits.some((unit) => (unit.symbol != null && unit.symbol.toLowerCase() === unitVal) || unit.label.toLowerCase() === unitVal || unit.aliases.some((alias) => alias.toLowerCase() === unitVal)))) { + this.customUnitWarning$.show(); + } else { + this.customUnitWarning$.hide(); + } + } + + onSupplierUnitChanged() { + const valueChosen = this.supplierUnitSelect$.val() !== undefined && this.supplierUnitSelect$.val().trim() !== ''; + this.unit$.prop('disabled', valueChosen); + this.unit$.toggle(!valueChosen); + this.filterAvailableRatioUnits(); + this.setMinimumOrderUnitDisplay(); + this.updateAvailableBillingAndGroupOrderUnits(); + this.updateUnitMultiplierLabels(); + } + + setMinimumOrderUnitDisplay() { + const chosenOptionLabel = this.supplierUnitSelect$.val() !== '' + ? $(`option[value="${this.supplierUnitSelect$.val()}"]`, this.supplierUnitSelect$).text() + : undefined; + const unitVal = $(`#${this.unitFieldsIdPrefix}_unit`).val(); + this.minimumOrderQuantity$ + .parents('.input-append') + .find('.add-on') + .text(chosenOptionLabel !== undefined ? chosenOptionLabel : unitVal); + + const converter = this.getUnitsConverter(); + this.minimumOrderQuantity$.attr('step', converter.isUnitSiConversible(this.supplierUnitSelect$.val()) ? 'any' : 1); + } + + bindAddRatioButton() { + $('*[data-add-ratio]', this.articleForm$).on('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + this.onAddRatioClicked(); + }); + } + + onAddRatioClicked() { + const newRow$ = this.articleUnitRatioTemplate$.clone(); + $('tbody', this.unitRatiosTable$).append(newRow$); + + const index = $(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[sort]"]`, this.articleForm$).length + + $(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[_destroy]"]`, this.articleForm$).length; + + const sortField$ = $('[name$="[sort]"]', newRow$); + sortField$.val(index); + + const ratioAttributeFields$ = $(`[id^="${this.unitFieldsIdPrefix}_article_unit_ratios_attributes_0_"]`, newRow$); + ratioAttributeFields$.each((_, field) => { + $(field).attr('name', $(field).attr('name').replace('[0]', `[${index}]`)); + $(field).attr('id', $(field).attr('id').replace(`${this.unitFieldsIdPrefix}_article_unit_ratios_attributes_0_`, `${this.unitFieldsIdPrefix}_article_unit_ratios_attributes_${index}_`)); + }); + + this.setFieldVisibility(); + + this.initializeRatioRows(); + } + + initializeRatioRows() { + $('tr', this.unitRatiosTable$).each((_, row) => { + this.initializeRatioRow($(row)); + }); + + this.updateUnitMultiplierLabels(); + this.filterAvailableRatioUnits(); + } + + initializeRatioRow(row$) { + $('*[data-remove-ratio]', row$) + .off('click.article_form_ratio_row') + .on('click.article_form_ratio_row', (e) => { + e.preventDefault(); + e.stopPropagation(); + this.removeRatioRow($(e.target).closest('tr')); + }); + + const select$ = $('select[name$="[unit]"]', row$); + select$.change(() => { + this.filterAvailableRatioUnits(row$) + this.updateUnitMultiplierLabels(); + }); + select$.select2(this.select2Config); + } + + updateUnitMultiplierLabels() { + $('tr', this.unitRatiosTable$).each((_, row) => { + const row$ = $(row); + const aboveUnit = this.findAboveUnit(row$); + $('.unit_multiplier', row$).text(aboveUnit); + }); + } + + removeRatioRow(row$) { + const index = row$.index() + 1; + const id = $(`[name="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes][${index}][id]"]`, this.articleForm$).val(); + row$.remove(); + + if (id != null) { + $(this.unitRatiosTable$).after($(``)); + $(this.unitRatiosTable$).after($(``)); + } + + this.filterAvailableRatioUnits(); + this.updateUnitMultiplierLabels(); + this.setFieldVisibility(); + } + + filterAvailableRatioUnits() { + const isUnitOrBaseUnitSelected = (unit, select$) => { + const code = select$.val(); + const selectedUnit = this.units[code]; + return unit.key !== code && (!unit.baseUnit || !selectedUnit || !selectedUnit.baseUnit || unit.baseUnit !== selectedUnit.baseUnit); + }; + + let remainingAvailableUnits = this.availableUnits.filter(unit => isUnitOrBaseUnitSelected(unit, this.supplierUnitSelect$)); + + $('tr select[name$="[unit]"]', this.unitRatiosTable$).each((_, unitSelect) => { + $('option[value!=""]' + remainingAvailableUnits.map(unit => `[value!="${unit.key}"]`).join(''), unitSelect).remove(); + const missingUnits = remainingAvailableUnits.filter(unit => $(`option[value="${unit.key}"]`, unitSelect).length === 0); + for (const missingUnit of missingUnits) { + $(unitSelect).append($(``)); + } + remainingAvailableUnits = remainingAvailableUnits.filter(unit => isUnitOrBaseUnitSelected(unit, $(unitSelect))); + }); + + this.updateAvailableBillingAndGroupOrderUnits(); + } + + findAboveUnit(row$) { + const previousRow$ = row$.prev(); + if (previousRow$.length > 0) { + const unitKey = previousRow$.find('select[name$="[unit]"]').val(); + const unit = this.availableUnits.find(availableUnit => availableUnit.key === unitKey); + if (!unit) { + return '?'; + } + return unit.label; + } else { + const unitKey = this.supplierUnitSelect$.val(); + if (unitKey !== '') { + const unit = this.availableUnits.find(availableUnit => availableUnit.key === unitKey); + if (!unit) { + return '?'; + } + return unit.label; + } else { + const unitVal = this.unit$.val(); + return unitVal ? unitVal : '?'; + } + } + } + + updateAvailableBillingAndGroupOrderUnits() { + const unitsSelectedAbove = []; + if (this.supplierUnitSelect$.val() != '') { + const chosenOption$ = $(`option[value="${this.supplierUnitSelect$.val()}"]`, this.supplierUnitSelect$); + unitsSelectedAbove.push({ key: chosenOption$.val(), label: chosenOption$.text() }); + } else { + const unitVal = this.unit$.val(); + unitsSelectedAbove.push({ key: '', label: unitVal ? unitVal : '?' }); + } + + const selectedRatioUnits = $('tr select[name$="[unit]"]', this.unitRatiosTable$).map((_, ratioSelect) => ({ + key: $(ratioSelect).val(), + label: $(`option[value="${$(ratioSelect).val()}"]`, ratioSelect).text() + })) + .get() + .filter(option => option.key !== ''); + + unitsSelectedAbove.push(...selectedRatioUnits); + + const availableUnits = []; + for (const unitSelectedAbove of unitsSelectedAbove) { + availableUnits.push(unitSelectedAbove, ...this.availableUnits.filter(availableUnit => { + if (availableUnit.key === unitSelectedAbove.key) { + return false; + } + + const otherUnit = this.availableUnits.find(unit => unit.key === unitSelectedAbove.key); + return otherUnit !== undefined && otherUnit.baseUnit !== null && availableUnit.baseUnit === otherUnit.baseUnit; + })); + } + + this.updateUnitsInSelect(availableUnits, this.billingUnit$); + this.billingUnit$.parents('.fold-line').css('display', availableUnits.length > 1 ? 'block' : 'none'); + this.updateUnitsInSelect(availableUnits, this.groupOrderUnit$); + this.updateUnitsInSelect(availableUnits, this.priceUnit$); + } + + updateUnitsInSelect(units, unitSelect$) { + const valueBeforeUpdate = unitSelect$.val(); + + unitSelect$.empty(); + for (const unit of units) { + unitSelect$.append($(``)); + } + + const initialValue = unitSelect$.attr('data-initial-value'); + if (initialValue) { + unitSelect$.val(initialValue); + unitSelect$.removeAttr('data-initial-value'); + } else { + if (unitSelect$.find(`option[value="${valueBeforeUpdate}"]`).length > 0) { + unitSelect$.val(valueBeforeUpdate); + } else { + unitSelect$.val(unitSelect$.find('option:first').val()); + } + } + + unitSelect$.trigger('change'); + + unitSelect$.parents('.control-group').find('.immutable_unit_label').remove(); + if (units.length === 1) { + unitSelect$.hide(); + unitSelect$.parents('.control-group').append($(`
${units[0].label}
`)) + } else { + unitSelect$.show(); + } + } + + setFieldVisibility() { + const firstUnitRatioQuantity$ = $('tr input[name$="[quantity]"]:first', this.unitRatiosTable$); + const firstUnitRatioUnit$ = $('tr select[name$="[unit]"]:first', this.unitRatiosTable$); + + const supplierOrderUnitSet = !!this.unit$.val() || !!this.supplierUnitSelect$.val(); + const unitRatiosVisible = supplierOrderUnitSet || this.unitRatiosTable$.find('tbody tr').length > 0; + this.unitRatiosTable$.parents('.fold-line').toggle(unitRatiosVisible); + + if (!unitRatiosVisible) { + $('tbody tr', this.unitRatiosTable$).remove(); + } + + mergeJQueryObjects([ + this.unit$, + this.supplierUnitSelect$, + firstUnitRatioQuantity$, + firstUnitRatioUnit$ + ]).off('change.article_form_visibility') + .on('change.article_form_visibility', () => + this.setFieldVisibility() + ); + + firstUnitRatioQuantity$ + .off('keyup.article_form_visibility') + .on('keyup.article_form_visibility', () => firstUnitRatioQuantity$.trigger('change')); + } + + prepareRatioDataForSequentialRepresentation() { + const indices = $(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[quantity]"]`) + .toArray() + .map((field) => parseInt(field.name.replace(/.+\[([0-9]+)\]\[quantity\]/, '$1'))); + const maxIndex = Math.max(...indices); + const minIndex = Math.min(...indices); + + for (let i = maxIndex; i > minIndex; i--) { + const currentField$ = $(`input[name="${this.ratioQuantityFieldNameByIndex(i)}"]`, this.articleForm$); + const currentValue = currentField$.val(); + const previousValue = $(`input[name="${this.ratioQuantityFieldNameByIndex(i - 1)}"]:last`, this.articleForm$).val(); + currentField$.val(round(currentValue / previousValue)); + } + } + + convertPriceToPriceUnit() { + const supplierUnitPrice = this.price$.val(); + const priceUnit = this.priceUnit$.val(); + if (priceUnit === undefined) { + return; + } + const ratio = this.getUnitRatio(1, priceUnit, this.supplierUnitSelect$.val()); + const relativePrice = round(supplierUnitPrice * ratio); + this.price$.val(relativePrice); + } + + initializeOrderedAndReceivedUnits() { + this.billingUnit$.change(() => { + this.updateOrderedAndReceivedUnits(); + this.initializeOrderedAndReceivedUnitsConverters(); + }); + this.billingUnit$.trigger('change'); + } + + updateOrderedAndReceivedUnits() { + const billingUnitKey = this.billingUnit$.val(); + const billingUnitLabel = this.getUnitLabel(billingUnitKey); + const inputs$ = mergeJQueryObjects([this.unitsToOrder$, this.unitsReceived$]); + inputs$.parent().find('.unit_label').remove(); + if (billingUnitLabel.trim() !== '') { + inputs$.after($(`${this.getUnitsConverter().isUnitSiConversible(billingUnitKey) ? '' : 'x '}${billingUnitLabel}`)); + } + if (this.previousBillingUnit !== undefined) { + this.convertOrderedAndReceivedUnits(this.previousBillingUnit, billingUnitKey); + } + this.previousBillingUnit = billingUnitKey; + } + + convertOrderedAndReceivedUnits(fromUnit, toUnit) { + const inputs$ = mergeJQueryObjects([this.unitsToOrder$, this.unitsReceived$]); + inputs$.each((_, input) => { + const input$ = $(input); + const val = input$.val(); + + if (val !== '') { + try { + const convertedValue = this.getUnitRatio(val, fromUnit, toUnit); + input$.val(round(convertedValue)); + } catch (e) { + // In some cases it's impossible to perform this conversion - just leave the original value + } + } + }); + } + + initializeOrderedAndReceivedUnitsConverters() { + this.unitsToOrder$.unitConversionField('destroy'); + this.unitsReceived$.unitConversionField('destroy'); + + const opts = { + units: this.units, + popoverTemplate$: this.unitConversionPopoverTemplate$, + ratios: this.ratios, + supplierOrderUnit: this.supplierUnitSelect$.val(), + customUnit: this.unit$.val(), + defaultUnit: this.billingUnit$.val() + }; + this.unitsToOrder$.unitConversionField(opts); + this.unitsReceived$.unitConversionField(opts); + } + + loadRatios() { + this.ratios = []; + this.unitRatiosTable$.find('tbody tr').each((_, element) => { + const tr$ = $(element); + const unit = tr$.find(`select[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[unit]"]`).val(); + const quantity = tr$.find(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[quantity]"]:last`).val(); + this.ratios.push({ unit, quantity }); + }); + } + + undoSequentialRatioDataRepresentation() { + let previousValue; + $(`input[name^="${this.unitFieldsNamePrefix}[article_unit_ratios_attributes]"][name$="[quantity]"]`).each((_, field) => { + let currentField$ = $(field); + let quantity = currentField$.val(); + + if (previousValue !== undefined) { + const td$ = currentField$.closest('td'); + const name = currentField$.attr('name'); + const ratioNameRegex = new RegExp(`${escapeForRegex(this.unitFieldsNamePrefix)}\\[article_unit_ratios_attributes\\]\\[([0-9]+)\\]`); + const index = name.match(ratioNameRegex)[1]; + quantity = quantity * previousValue; + currentField$ = $(``); + td$.append(currentField$); + } + + previousValue = quantity; + }); + } + + ratioQuantityFieldNameByIndex(i) { + return `${this.unitFieldsNamePrefix}[article_unit_ratios_attributes][${i}][quantity]`; + } + + enableSubmitButton() { + this.submitButton$.removeAttr('disabled'); + } +} + + +// TODO: Move those functions to some global js utils file (see https://github.com/foodcoopsat/foodsoft_hackathon/issues/88): +function mergeJQueryObjects(array_of_jquery_objects) { + return $($.map(array_of_jquery_objects, function (el) { + return el.get(); + })); +} + +function round(num, precision) { + if (precision === undefined) { + precision = 3; + } + const factor = Math.pow(10, precision); + return Math.round((num + Number.EPSILON) * factor) / factor; +} + +function escapeForRegex(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} diff --git a/app/assets/javascripts/big.js b/app/assets/javascripts/big.js new file mode 100644 index 000000000..2f2be0348 --- /dev/null +++ b/app/assets/javascripts/big.js @@ -0,0 +1,1043 @@ +/* + * big.js v6.2.1 + * A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic. + * Copyright (c) 2022 Michael Mclaughlin + * https://github.com/MikeMcl/big.js/LICENCE.md + */ +(function (GLOBAL) { + 'use strict'; + var Big, + + +/************************************** EDITABLE DEFAULTS *****************************************/ + + + // The default values below must be integers within the stated ranges. + + /* + * The maximum number of decimal places (DP) of the results of operations involving division: + * div and sqrt, and pow with negative exponents. + */ + DP = 20, // 0 to MAX_DP + + /* + * The rounding mode (RM) used when rounding to the above decimal places. + * + * 0 Towards zero (i.e. truncate, no rounding). (ROUND_DOWN) + * 1 To nearest neighbour. If equidistant, round up. (ROUND_HALF_UP) + * 2 To nearest neighbour. If equidistant, to even. (ROUND_HALF_EVEN) + * 3 Away from zero. (ROUND_UP) + */ + RM = 1, // 0, 1, 2 or 3 + + // The maximum value of DP and Big.DP. + MAX_DP = 1E6, // 0 to 1000000 + + // The maximum magnitude of the exponent argument to the pow method. + MAX_POWER = 1E6, // 1 to 1000000 + + /* + * The negative exponent (NE) at and beneath which toString returns exponential notation. + * (JavaScript numbers: -7) + * -1000000 is the minimum recommended exponent value of a Big. + */ + NE = -7, // 0 to -1000000 + + /* + * The positive exponent (PE) at and above which toString returns exponential notation. + * (JavaScript numbers: 21) + * 1000000 is the maximum recommended exponent value of a Big, but this limit is not enforced. + */ + PE = 21, // 0 to 1000000 + + /* + * When true, an error will be thrown if a primitive number is passed to the Big constructor, + * or if valueOf is called, or if toNumber is called on a Big which cannot be converted to a + * primitive number without a loss of precision. + */ + STRICT = false, // true or false + + +/**************************************************************************************************/ + + + // Error messages. + NAME = '[big.js] ', + INVALID = NAME + 'Invalid ', + INVALID_DP = INVALID + 'decimal places', + INVALID_RM = INVALID + 'rounding mode', + DIV_BY_ZERO = NAME + 'Division by zero', + + // The shared prototype object. + P = {}, + UNDEFINED = void 0, + NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; + + + /* + * Create and return a Big constructor. + */ + function _Big_() { + + /* + * The Big constructor and exported function. + * Create and return a new instance of a Big number object. + * + * n {number|string|Big} A numeric value. + */ + function Big(n) { + var x = this; + + // Enable constructor usage without new. + if (!(x instanceof Big)) return n === UNDEFINED ? _Big_() : new Big(n); + + // Duplicate. + if (n instanceof Big) { + x.s = n.s; + x.e = n.e; + x.c = n.c.slice(); + } else { + if (typeof n !== 'string') { + if (Big.strict === true && typeof n !== 'bigint') { + throw TypeError(INVALID + 'value'); + } + + // Minus zero? + n = n === 0 && 1 / n < 0 ? '-0' : String(n); + } + + parse(x, n); + } + + // Retain a reference to this Big constructor. + // Shadow Big.prototype.constructor which points to Object. + x.constructor = Big; + } + + Big.prototype = P; + Big.DP = DP; + Big.RM = RM; + Big.NE = NE; + Big.PE = PE; + Big.strict = STRICT; + Big.roundDown = 0; + Big.roundHalfUp = 1; + Big.roundHalfEven = 2; + Big.roundUp = 3; + + return Big; + } + + + /* + * Parse the number or string value passed to a Big constructor. + * + * x {Big} A Big number instance. + * n {number|string} A numeric value. + */ + function parse(x, n) { + var e, i, nl; + + if (!NUMERIC.test(n)) { + throw Error(INVALID + 'number'); + } + + // Determine sign. + x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1; + + // Decimal point? + if ((e = n.indexOf('.')) > -1) n = n.replace('.', ''); + + // Exponential form? + if ((i = n.search(/e/i)) > 0) { + + // Determine exponent. + if (e < 0) e = i; + e += +n.slice(i + 1); + n = n.substring(0, i); + } else if (e < 0) { + + // Integer. + e = n.length; + } + + nl = n.length; + + // Determine leading zeros. + for (i = 0; i < nl && n.charAt(i) == '0';) ++i; + + if (i == nl) { + + // Zero. + x.c = [x.e = 0]; + } else { + + // Determine trailing zeros. + for (; nl > 0 && n.charAt(--nl) == '0';); + x.e = e - i - 1; + x.c = []; + + // Convert string to array of digits without leading/trailing zeros. + for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++); + } + + return x; + } + + + /* + * Round Big x to a maximum of sd significant digits using rounding mode rm. + * + * x {Big} The Big to round. + * sd {number} Significant digits: integer, 0 to MAX_DP inclusive. + * rm {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + * [more] {boolean} Whether the result of division was truncated. + */ + function round(x, sd, rm, more) { + var xc = x.c; + + if (rm === UNDEFINED) rm = x.constructor.RM; + if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) { + throw Error(INVALID_RM); + } + + if (sd < 1) { + more = + rm === 3 && (more || !!xc[0]) || sd === 0 && ( + rm === 1 && xc[0] >= 5 || + rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED)) + ); + + xc.length = 1; + + if (more) { + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + x.e = x.e - sd + 1; + xc[0] = 1; + } else { + + // Zero. + xc[0] = x.e = 0; + } + } else if (sd < xc.length) { + + // xc[sd] is the digit after the digit that may be rounded up. + more = + rm === 1 && xc[sd] >= 5 || + rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && + (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || + rm === 3 && (more || !!xc[0]); + + // Remove any digits after the required precision. + xc.length = sd; + + // Round up? + if (more) { + + // Rounding up may mean the previous digit has to be rounded up. + for (; ++xc[--sd] > 9;) { + xc[sd] = 0; + if (sd === 0) { + ++x.e; + xc.unshift(1); + break; + } + } + } + + // Remove trailing zeros. + for (sd = xc.length; !xc[--sd];) xc.pop(); + } + + return x; + } + + + /* + * Return a string representing the value of Big x in normal or exponential notation. + * Handles P.toExponential, P.toFixed, P.toJSON, P.toPrecision, P.toString and P.valueOf. + */ + function stringify(x, doExponential, isNonzero) { + var e = x.e, + s = x.c.join(''), + n = s.length; + + // Exponential notation? + if (doExponential) { + s = s.charAt(0) + (n > 1 ? '.' + s.slice(1) : '') + (e < 0 ? 'e' : 'e+') + e; + + // Normal notation. + } else if (e < 0) { + for (; ++e;) s = '0' + s; + s = '0.' + s; + } else if (e > 0) { + if (++e > n) { + for (e -= n; e--;) s += '0'; + } else if (e < n) { + s = s.slice(0, e) + '.' + s.slice(e); + } + } else if (n > 1) { + s = s.charAt(0) + '.' + s.slice(1); + } + + return x.s < 0 && isNonzero ? '-' + s : s; + } + + + // Prototype/instance methods + + + /* + * Return a new Big whose value is the absolute value of this Big. + */ + P.abs = function () { + var x = new this.constructor(this); + x.s = 1; + return x; + }; + + + /* + * Return 1 if the value of this Big is greater than the value of Big y, + * -1 if the value of this Big is less than the value of Big y, or + * 0 if they have the same value. + */ + P.cmp = function (y) { + var isneg, + x = this, + xc = x.c, + yc = (y = new x.constructor(y)).c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + + // Either zero? + if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i; + + // Signs differ? + if (i != j) return i; + + isneg = i < 0; + + // Compare exponents. + if (k != l) return k > l ^ isneg ? 1 : -1; + + j = (k = xc.length) < (l = yc.length) ? k : l; + + // Compare digit by digit. + for (i = -1; ++i < j;) { + if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; + } + + // Compare lengths. + return k == l ? 0 : k > l ^ isneg ? 1 : -1; + }; + + + /* + * Return a new Big whose value is the value of this Big divided by the value of Big y, rounded, + * if necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. + */ + P.div = function (y) { + var x = this, + Big = x.constructor, + a = x.c, // dividend + b = (y = new Big(y)).c, // divisor + k = x.s == y.s ? 1 : -1, + dp = Big.DP; + + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + + // Divisor is zero? + if (!b[0]) { + throw Error(DIV_BY_ZERO); + } + + // Dividend is 0? Return +-0. + if (!a[0]) { + y.s = k; + y.c = [y.e = 0]; + return y; + } + + var bl, bt, n, cmp, ri, + bz = b.slice(), + ai = bl = b.length, + al = a.length, + r = a.slice(0, bl), // remainder + rl = r.length, + q = y, // quotient + qc = q.c = [], + qi = 0, + p = dp + (q.e = x.e - y.e) + 1; // precision of the result + + q.s = k; + k = p < 0 ? 0 : p; + + // Create version of divisor with leading zero. + bz.unshift(0); + + // Add zeros to make remainder as long as divisor. + for (; rl++ < bl;) r.push(0); + + do { + + // n is how many times the divisor goes into current remainder. + for (n = 0; n < 10; n++) { + + // Compare divisor and remainder. + if (bl != (rl = r.length)) { + cmp = bl > rl ? 1 : -1; + } else { + for (ri = -1, cmp = 0; ++ri < bl;) { + if (b[ri] != r[ri]) { + cmp = b[ri] > r[ri] ? 1 : -1; + break; + } + } + } + + // If divisor < remainder, subtract divisor from remainder. + if (cmp < 0) { + + // Remainder can't be more than 1 digit longer than divisor. + // Equalise lengths using divisor with extra leading zero? + for (bt = rl == bl ? b : bz; rl;) { + if (r[--rl] < bt[rl]) { + ri = rl; + for (; ri && !r[--ri];) r[ri] = 9; + --r[ri]; + r[rl] += 10; + } + r[rl] -= bt[rl]; + } + + for (; !r[0];) r.shift(); + } else { + break; + } + } + + // Add the digit n to the result array. + qc[qi++] = cmp ? n : ++n; + + // Update the remainder. + if (r[0] && cmp) r[rl] = a[ai] || 0; + else r = [a[ai]]; + + } while ((ai++ < al || r[0] !== UNDEFINED) && k--); + + // Leading zero? Do not remove if result is simply zero (qi == 1). + if (!qc[0] && qi != 1) { + + // There can't be more than one zero. + qc.shift(); + q.e--; + p--; + } + + // Round? + if (qi > p) round(q, p, Big.RM, r[0] !== UNDEFINED); + + return q; + }; + + + /* + * Return true if the value of this Big is equal to the value of Big y, otherwise return false. + */ + P.eq = function (y) { + return this.cmp(y) === 0; + }; + + + /* + * Return true if the value of this Big is greater than the value of Big y, otherwise return + * false. + */ + P.gt = function (y) { + return this.cmp(y) > 0; + }; + + + /* + * Return true if the value of this Big is greater than or equal to the value of Big y, otherwise + * return false. + */ + P.gte = function (y) { + return this.cmp(y) > -1; + }; + + + /* + * Return true if the value of this Big is less than the value of Big y, otherwise return false. + */ + P.lt = function (y) { + return this.cmp(y) < 0; + }; + + + /* + * Return true if the value of this Big is less than or equal to the value of Big y, otherwise + * return false. + */ + P.lte = function (y) { + return this.cmp(y) < 1; + }; + + + /* + * Return a new Big whose value is the value of this Big minus the value of Big y. + */ + P.minus = P.sub = function (y) { + var i, j, t, xlty, + x = this, + Big = x.constructor, + a = x.s, + b = (y = new Big(y)).s; + + // Signs differ? + if (a != b) { + y.s = -b; + return x.plus(y); + } + + var xc = x.c.slice(), + xe = x.e, + yc = y.c, + ye = y.e; + + // Either zero? + if (!xc[0] || !yc[0]) { + if (yc[0]) { + y.s = -b; + } else if (xc[0]) { + y = new Big(x); + } else { + y.s = 1; + } + return y; + } + + // Determine which is the bigger number. Prepend zeros to equalise exponents. + if (a = xe - ye) { + + if (xlty = a < 0) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + + t.reverse(); + for (b = a; b--;) t.push(0); + t.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ((xlty = xc.length < yc.length) ? xc : yc).length; + + for (a = b = 0; b < j; b++) { + if (xc[b] != yc[b]) { + xlty = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if (xlty) { + t = xc; + xc = yc; + yc = t; + y.s = -y.s; + } + + /* + * Append zeros to xc if shorter. No need to add zeros to yc if shorter as subtraction only + * needs to start at yc.length. + */ + if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--;) xc[i++] = 0; + + // Subtract yc from xc. + for (b = i; j > a;) { + if (xc[--j] < yc[j]) { + for (i = j; i && !xc[--i];) xc[i] = 9; + --xc[i]; + xc[j] += 10; + } + + xc[j] -= yc[j]; + } + + // Remove trailing zeros. + for (; xc[--b] === 0;) xc.pop(); + + // Remove leading zeros and adjust exponent accordingly. + for (; xc[0] === 0;) { + xc.shift(); + --ye; + } + + if (!xc[0]) { + + // n - n = +0 + y.s = 1; + + // Result must be zero. + xc = [ye = 0]; + } + + y.c = xc; + y.e = ye; + + return y; + }; + + + /* + * Return a new Big whose value is the value of this Big modulo the value of Big y. + */ + P.mod = function (y) { + var ygtx, + x = this, + Big = x.constructor, + a = x.s, + b = (y = new Big(y)).s; + + if (!y.c[0]) { + throw Error(DIV_BY_ZERO); + } + + x.s = y.s = 1; + ygtx = y.cmp(x) == 1; + x.s = a; + y.s = b; + + if (ygtx) return new Big(x); + + a = Big.DP; + b = Big.RM; + Big.DP = Big.RM = 0; + x = x.div(y); + Big.DP = a; + Big.RM = b; + + return this.minus(x.times(y)); + }; + + + /* + * Return a new Big whose value is the value of this Big negated. + */ + P.neg = function () { + var x = new this.constructor(this); + x.s = -x.s; + return x; + }; + + + /* + * Return a new Big whose value is the value of this Big plus the value of Big y. + */ + P.plus = P.add = function (y) { + var e, k, t, + x = this, + Big = x.constructor; + + y = new Big(y); + + // Signs differ? + if (x.s != y.s) { + y.s = -y.s; + return x.minus(y); + } + + var xe = x.e, + xc = x.c, + ye = y.e, + yc = y.c; + + // Either zero? + if (!xc[0] || !yc[0]) { + if (!yc[0]) { + if (xc[0]) { + y = new Big(x); + } else { + y.s = x.s; + } + } + return y; + } + + xc = xc.slice(); + + // Prepend zeros to equalise exponents. + // Note: reverse faster than unshifts. + if (e = xe - ye) { + if (e > 0) { + ye = xe; + t = yc; + } else { + e = -e; + t = xc; + } + + t.reverse(); + for (; e--;) t.push(0); + t.reverse(); + } + + // Point xc to the longer array. + if (xc.length - yc.length < 0) { + t = yc; + yc = xc; + xc = t; + } + + e = yc.length; + + // Only start adding at yc.length - 1 as the further digits of xc can be left as they are. + for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0; + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + + if (k) { + xc.unshift(k); + ++ye; + } + + // Remove trailing zeros. + for (e = xc.length; xc[--e] === 0;) xc.pop(); + + y.c = xc; + y.e = ye; + + return y; + }; + + + /* + * Return a Big whose value is the value of this Big raised to the power n. + * If n is negative, round to a maximum of Big.DP decimal places using rounding + * mode Big.RM. + * + * n {number} Integer, -MAX_POWER to MAX_POWER inclusive. + */ + P.pow = function (n) { + var x = this, + one = new x.constructor('1'), + y = one, + isneg = n < 0; + + if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) { + throw Error(INVALID + 'exponent'); + } + + if (isneg) n = -n; + + for (;;) { + if (n & 1) y = y.times(x); + n >>= 1; + if (!n) break; + x = x.times(x); + } + + return isneg ? one.div(y) : y; + }; + + + /* + * Return a new Big whose value is the value of this Big rounded to a maximum precision of sd + * significant digits using rounding mode rm, or Big.RM if rm is not specified. + * + * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P.prec = function (sd, rm) { + if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { + throw Error(INVALID + 'precision'); + } + return round(new this.constructor(this), sd, rm); + }; + + + /* + * Return a new Big whose value is the value of this Big rounded to a maximum of dp decimal places + * using rounding mode rm, or Big.RM if rm is not specified. + * If dp is negative, round to an integer which is a multiple of 10**-dp. + * If dp is not specified, round to 0 decimal places. + * + * dp? {number} Integer, -MAX_DP to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P.round = function (dp, rm) { + if (dp === UNDEFINED) dp = 0; + else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) { + throw Error(INVALID_DP); + } + return round(new this.constructor(this), dp + this.e + 1, rm); + }; + + + /* + * Return a new Big whose value is the square root of the value of this Big, rounded, if + * necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM. + */ + P.sqrt = function () { + var r, c, t, + x = this, + Big = x.constructor, + s = x.s, + e = x.e, + half = new Big('0.5'); + + // Zero? + if (!x.c[0]) return new Big(x); + + // Negative? + if (s < 0) { + throw Error(NAME + 'No square root'); + } + + // Estimate. + s = Math.sqrt(x + ''); + + // Math.sqrt underflow/overflow? + // Re-estimate: pass x coefficient to Math.sqrt as integer, then adjust the result exponent. + if (s === 0 || s === 1 / 0) { + c = x.c.join(''); + if (!(c.length + e & 1)) c += '0'; + s = Math.sqrt(c); + e = ((e + 1) / 2 | 0) - (e < 0 || e & 1); + r = new Big((s == 1 / 0 ? '5e' : (s = s.toExponential()).slice(0, s.indexOf('e') + 1)) + e); + } else { + r = new Big(s + ''); + } + + e = r.e + (Big.DP += 4); + + // Newton-Raphson iteration. + do { + t = r; + r = half.times(t.plus(x.div(t))); + } while (t.c.slice(0, e).join('') !== r.c.slice(0, e).join('')); + + return round(r, (Big.DP -= 4) + r.e + 1, Big.RM); + }; + + + /* + * Return a new Big whose value is the value of this Big times the value of Big y. + */ + P.times = P.mul = function (y) { + var c, + x = this, + Big = x.constructor, + xc = x.c, + yc = (y = new Big(y)).c, + a = xc.length, + b = yc.length, + i = x.e, + j = y.e; + + // Determine sign of result. + y.s = x.s == y.s ? 1 : -1; + + // Return signed 0 if either 0. + if (!xc[0] || !yc[0]) { + y.c = [y.e = 0]; + return y; + } + + // Initialise exponent of result as x.e + y.e. + y.e = i + j; + + // If array xc has fewer digits than yc, swap xc and yc, and lengths. + if (a < b) { + c = xc; + xc = yc; + yc = c; + j = a; + a = b; + b = j; + } + + // Initialise coefficient array of result with zeros. + for (c = new Array(j = a + b); j--;) c[j] = 0; + + // Multiply. + + // i is initially xc.length. + for (i = b; i--;) { + b = 0; + + // a is yc.length. + for (j = a + i; j > i;) { + + // Current sum of products at this digit position, plus carry. + b = c[j] + yc[i] * xc[j - i - 1] + b; + c[j--] = b % 10; + + // carry + b = b / 10 | 0; + } + + c[j] = b; + } + + // Increment result exponent if there is a final carry, otherwise remove leading zero. + if (b) ++y.e; + else c.shift(); + + // Remove trailing zeros. + for (i = c.length; !c[--i];) c.pop(); + y.c = c; + + return y; + }; + + + /* + * Return a string representing the value of this Big in exponential notation rounded to dp fixed + * decimal places using rounding mode rm, or Big.RM if rm is not specified. + * + * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P.toExponential = function (dp, rm) { + var x = this, + n = x.c[0]; + + if (dp !== UNDEFINED) { + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + x = round(new x.constructor(x), ++dp, rm); + for (; x.c.length < dp;) x.c.push(0); + } + + return stringify(x, true, !!n); + }; + + + /* + * Return a string representing the value of this Big in normal notation rounded to dp fixed + * decimal places using rounding mode rm, or Big.RM if rm is not specified. + * + * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + * + * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. + * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. + */ + P.toFixed = function (dp, rm) { + var x = this, + n = x.c[0]; + + if (dp !== UNDEFINED) { + if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { + throw Error(INVALID_DP); + } + x = round(new x.constructor(x), dp + x.e + 1, rm); + + // x.e may have changed if the value is rounded up. + for (dp = dp + x.e + 1; x.c.length < dp;) x.c.push(0); + } + + return stringify(x, false, !!n); + }; + + + /* + * Return a string representing the value of this Big. + * Return exponential notation if this Big has a positive exponent equal to or greater than + * Big.PE, or a negative exponent equal to or less than Big.NE. + * Omit the sign for negative zero. + */ + P.toJSON = P.toString = function () { + var x = this, + Big = x.constructor; + return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0]); + }; + + + /* + * Return the value of this Big as a primitve number. + */ + P.toNumber = function () { + var n = Number(stringify(this, true, true)); + if (this.constructor.strict === true && !this.eq(n.toString())) { + throw Error(NAME + 'Imprecise conversion'); + } + return n; + }; + + + /* + * Return a string representing the value of this Big rounded to sd significant digits using + * rounding mode rm, or Big.RM if rm is not specified. + * Use exponential notation if sd is less than the number of digits necessary to represent + * the integer part of the value in normal notation. + * + * sd {number} Significant digits: integer, 1 to MAX_DP inclusive. + * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up). + */ + P.toPrecision = function (sd, rm) { + var x = this, + Big = x.constructor, + n = x.c[0]; + + if (sd !== UNDEFINED) { + if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { + throw Error(INVALID + 'precision'); + } + x = round(new Big(x), sd, rm); + for (; x.c.length < sd;) x.c.push(0); + } + + return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n); + }; + + + /* + * Return a string representing the value of this Big. + * Return exponential notation if this Big has a positive exponent equal to or greater than + * Big.PE, or a negative exponent equal to or less than Big.NE. + * Include the sign for negative zero. + */ + P.valueOf = function () { + var x = this, + Big = x.constructor; + if (Big.strict === true) { + throw Error(NAME + 'valueOf disallowed'); + } + return stringify(x, x.e <= Big.NE || x.e >= Big.PE, true); + }; + + + // Export + + + Big = _Big_(); + + Big['default'] = Big.Big = Big; + + //AMD. + if (typeof define === 'function' && define.amd) { + define(function () { return Big; }); + + // Node and other CommonJS-like environments that support module.exports. + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Big; + + //Browser. + } else { + GLOBAL.Big = Big; + } +})(this); diff --git a/app/assets/javascripts/delta_input.js b/app/assets/javascripts/delta_input.js index d0da30d8a..ddfb8c872 100644 --- a/app/assets/javascripts/delta_input.js +++ b/app/assets/javascripts/delta_input.js @@ -6,7 +6,7 @@ $(function() { $(document).on('click', 'button[data-decrement]', function() { data_delta_update($('#'+$(this).data('decrement')), -1); }); - $(document).on('change keyup', 'input[type="text"][data-delta]', function() { + $(document).on('change keyup', 'input[type="number"][data-delta]', function() { data_delta_update(this, 0); }); }); @@ -20,6 +20,7 @@ function data_delta_update(el, direction) { var granularity = $(el).data('granularity'); var val = $(el).val().replace(',', '.'); + const valueContainedColon = $(el).val() != val; var oldval = $.isNumeric(val) ? Number(val) : 0; var newval = oldval + delta*direction; @@ -36,7 +37,11 @@ function data_delta_update(el, direction) { // update field, unless the user is typing if (!$(el).is(':focus') && !erroneousValue) { - $(el).val(round_float(newval, granularity)); + let roundedValue = String(round_float(newval, granularity)); + if (valueContainedColon) { + roundedValue = roundedValue.replace('.', ','); + } + $(el).val(roundedValue); $(el).trigger('changed'); } } diff --git a/app/assets/javascripts/group-order-form.js b/app/assets/javascripts/group-order-form.js new file mode 100644 index 000000000..5e6945398 --- /dev/null +++ b/app/assets/javascripts/group-order-form.js @@ -0,0 +1,230 @@ +class GroupOrderForm { + constructor(form$, config) { + this.form$ = form$; + this.articleRows$ = this.form$.find('tr.order-article'); + this.totalPrice$ = this.form$.find('#total_price'); + this.newBalance$ = this.form$.find('#new_balance'); + this.totalBalance$ = this.form$.find('#total_balance'); + this.submitButton$ = this.form$.find('#submit_button'); + this.units = config.units; + this.toleranceIsCostly = config.toleranceIsCostly; + this.groupBalance = config.groupBalance; + this.minimumBalance = config.minimumBalance; + + this.initializeIncreaseDecreaseButtons(); + this.submitButton$.removeAttr('disabled'); + } + + initializeIncreaseDecreaseButtons() { + this.articleRows$.each((_, element) => this.initializeOrderArticleRow($(element))); + } + + initializeOrderArticleRow(row$) { + const quantity$ = row$.find('.goa-quantity'); + const tolerance$ = row$.find('.goa-tolerance'); + // eslint-disable-next-line no-undef + const quantityAndTolerance$ = mergeJQueryObjects([quantity$, tolerance$]); + // eslint-disable-next-line no-undef + quantityAndTolerance$.each((_, element) => $(element).unitConversionField({ + units: this.units, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + })); + row$.find('.btn-ordering').mousedown((e) => e.preventDefault()); + row$.find('.btn-ordering.decrease').click((event) => this.increaseOrDecrease($(event.target).parents('.btn-group').find('input.numeric'), false)); + row$.find('.btn-ordering.increase').click((event) => this.increaseOrDecrease($(event.target).parents('.btn-group').find('input.numeric'), true)); + + quantityAndTolerance$.change(() => { + this.updateMissingUnits(row$, quantity$); + this.updateBalance(); + }); + quantityAndTolerance$.keyup(() => quantity$.trigger('change')); + } + + updateBalance() { + const total = this.articleRows$ + .toArray() + .reduce((acc, row) => + Big(acc).add(parseFloat($(row).find('*[id^="price_"][id$="_display"]').data('price'))).toNumber(), + 0 + ); + + this.totalPrice$.text(I18n.l('currency', total)); + const balance = Big(this.groupBalance).sub(total).toNumber(); + this.newBalance$.text(I18n.l('currency', balance)); + + // TODO: Figure out why this hidden field is required (Should be + // calculated in the controller IMO! - see https://github.com/foodcoopsat/foodsoft_hackathon/issues/97): + this.totalBalance$.val(I18n.l('currency', balance)); + + // determine bgcolor and submit button state according to balance + var bgcolor = ''; + if (balance < this.minimumBalance) { + bgcolor = '#FF0000'; + this.submitButton$.attr('disabled', 'disabled') + } else { + this.submitButton$.removeAttr('disabled') + } + + // update bgcolor + this.articleRows$.find('*[id^="td_price_"]').css('background-color', bgcolor); + } + + increaseOrDecrease(field$, increase) { + let step = parseFloat(field$.attr('step')); + if (isNaN(step)) { + step = 1; + } + if (!increase) { + step *= -1; + } + let value = parseFloat(field$.val()); + + if (isNaN(value)) { + value = 0; + } + + value = round(value + step); + let remainder = round(value % step); + if (remainder !== 0) { + if (!increase) { + remainder *= -1; + } + value += remainder - step; + } + const min = field$.attr('min'); + if (min !== undefined) { + value = Math.max(parseFloat(min), value); + } + + const max = field$.attr('max'); + if (max !== undefined) { + value = Math.min(parseFloat(max), value); + } + + field$.val(value); + field$.trigger('change'); + } + + updateMissingUnits(row$) { + const used$ = row$.find('.used-unused .used'); + const unused$ = row$.find('.used-unused .unused'); + + const quantity$ = row$.find('.goa-quantity'); + const tolerance$ = row$.find('.goa-tolerance'); + const usedTolerance$ = row$.find('.used-unused-tolerance .used'); + const unusedTolerance$ = row$.find('.used-unused-tolerance .unused'); + const totalPacks$ = row$.find('.article-info *[id^="units_"]'); + const totalQuantity$ = row$.find('.article-info *[id^="q_total_"]'); + const totalTolerance$ = row$.find('.article-info *[id^="t_total_"]'); + const totalPrice$ = row$.find('*[id^="price_"][id$="_display"]'); + + const missing$ = row$.find('.missing-units'); + + let quantity = parseFloat(quantity$.val().trim().replace(',', '.')); + if (isNaN(quantity)) { + quantity = 0; + } + const granularity = parseFloat(quantity$.attr('step')); + let tolerance = tolerance$.length === 1 ? parseFloat(tolerance$.val().trim().replace(',', '.')) : 0; + if (isNaN(tolerance)) { + tolerance = 0; + } + const supplierOrderUnit = quantity$.data('supplier-order-unit'); + const converter = quantity$.unitConversionField('getConverter'); + const packSizeDeterminedBySupplierOrderUnit = converter && !converter.isUnitSiConversible(supplierOrderUnit); + + const packSize = packSizeDeterminedBySupplierOrderUnit ? parseFloat(quantity$.data('ratio-group-order-unit-supplier-unit')) : 0.001; + const othersQuantity = parseFloat(quantity$.data('others-quantity')); + const othersTolerance = parseFloat(quantity$.data('others-tolerance')); + const usedQuantity = parseFloat(quantity$.data('used-quantity')); + const minimumOrderQuantity = parseFloat(quantity$.data('minimum-order-quantity')); + const price = parseFloat(quantity$.data('price')); + + const totalQuantity = Big(quantity).add(othersQuantity).toNumber(); + const totalTolerance = Big(tolerance).add(othersTolerance).toNumber(); + + const totalPacks = this.calculatePacks(packSize, totalQuantity, totalTolerance, minimumOrderQuantity) + + const totalPrice = Big(price).mul(Big(quantity).add(this.toleranceIsCostly ? tolerance : 0)).toNumber(); + + // update used/unused quantity + const available = Math.max(0, Big(totalPacks).mul(packSize).sub(othersQuantity).toNumber()); + let used = Math.min(available, quantity); + // ensure that at least the amount of items this group has already been allocated is used + if (quantity >= usedQuantity && used < usedQuantity) { + used = usedQuantity; + } + + const unused = Big(quantity).sub(used).toNumber(); + + const availableForTolerance = quantity < minimumOrderQuantity ? Big(minimumOrderQuantity).sub(quantity).toNumber() : Math.max(0, Big(available).sub(used).sub(othersTolerance).toNumber()); + const usedTolerance = Math.min(availableForTolerance, tolerance); + const unusedTolerance = Big(tolerance).sub(usedTolerance).toNumber(); + + const missing = this.calcMissingItems(packSize, totalQuantity, totalTolerance, minimumOrderQuantity); + + used$.text(round(used)); + unused$.text(round(unused)); + + usedTolerance$.text(round(usedTolerance)); + unusedTolerance$.text(round(unusedTolerance)); + + totalPacks$.text(packSizeDeterminedBySupplierOrderUnit ? round(totalPacks) : round(totalQuantity)); + + totalPacks$.css('color', this.packCompletedFromTolerance(packSize, totalQuantity, totalTolerance) ? 'grey' : 'auto'); + + totalQuantity$.text(round(totalQuantity)); + totalTolerance$.text(round(totalTolerance)); + totalPrice$.text(I18n.l('currency', round(totalPrice))); + totalPrice$.data('price', round(totalPrice)); + + missing$.text(round(missing)); + if (tolerance$.length === 1) { + this.setRowStyle(row$, missing, granularity, quantity); + } + } + + setRowStyle(row$, missing, granularity, quantity) { + row$.removeClass('missing-many missing-few missing-none'); + if (missing === 0) { + if (quantity !== 0) { + row$.addClass('missing-none'); + } + } else { + row$.addClass(missing <= granularity ? 'missing-few' : 'missing-many'); + } + } + + calculatePacks(packSize, quantity, tolerance, minimumOrderQuantity) { + if (Big(quantity).add(tolerance).toNumber() < minimumOrderQuantity) { + return 0; + } + + const used = Big(quantity).div(packSize).round(0, Big.roundDown).toNumber(); + const remainder = Big(quantity).mod(packSize).toNumber(); + return Big(used).add((remainder > 0) && (Big(remainder).add(tolerance).toNumber() >= packSize) ? 1 : 0).toNumber(); + } + + calcMissingItems(packSize, quantity, tolerance, minimumOrderQuantity) { + if (quantity !== 0 && Big(quantity).add(tolerance).toNumber() < minimumOrderQuantity) { + return Big(minimumOrderQuantity).sub(quantity).sub(tolerance).toNumber(); + } + + if (isNaN(quantity)) { + return quantity; + } + + if (isNaN(packSize)) { + return packSize; + } + + var remainder = Big(quantity).mod(packSize).toNumber(); + return remainder > 0 && Big(remainder).add(tolerance).toNumber() < packSize ? Big(packSize).sub(remainder).sub(tolerance).toNumber() : 0 + } + + packCompletedFromTolerance(packSize, quantity, tolerance) { + var remainder = Big(quantity).mod(packSize).toNumber(); + return (remainder > 0 && (Big(remainder).add(tolerance).toNumber() >= packSize)); + } +} + diff --git a/app/assets/javascripts/migrate-units-form.js b/app/assets/javascripts/migrate-units-form.js new file mode 100644 index 000000000..87d06da6d --- /dev/null +++ b/app/assets/javascripts/migrate-units-form.js @@ -0,0 +1,142 @@ +class MigrateUnitsForm { + constructor(articleUnitRatioTemplate$, table$, units) { + this.articleUnitRatioTemplate$ = articleUnitRatioTemplate$; + this.table$ = table$; + this.units = units; + + this.initializeUnitSelects(); + this.initializeArticlesList(); + } + + loadAvailableUnits() { + this.availableUnits = Object.entries(this.units) + .filter(([, unit]) => unit.visible) + .map(([code, unit]) => ({ key: code, label: unit.name, baseUnit: unit.baseUnit, symbol: unit.symbol, aliases: unit.aliases ? unit.aliases : [] })); + } + + initializeUnitSelects() { + this.loadAvailableUnits(); + this.table$.find('select[name^="samples["]').select2(); + const form = this; + this.table$.find('select[name^="samples["][name$="[supplier_order_unit]"]').each(function() { + form.updateUnitsInSelect(form.availableUnits, $(this)); + form.updateFirstUnitRatioSelect($(this).parents('tr')); + form.updateGroupOrderUnitSelect($(this).parents('tr')); + form.updateFirstUnitRatioQuantity($(this).parents('tr')); + }); + this.table$.find('select[name^="samples["][name$="[supplier_order_unit]"]').change(function() { + form.updateFirstUnitRatioSelect($(this).parents('tr')); + form.updateGroupOrderUnitSelect($(this).parents('tr')); + form.updateFirstUnitRatioQuantity($(this).parents('tr')); + }); + this.table$.find('select[name^="samples["][name$="[first_ratio_unit]"]').change(function() { + form.updateGroupOrderUnitSelect($(this).parents('tr')); + form.updateFirstUnitRatioQuantity($(this).parents('tr')); + }); + } + + updateFirstUnitRatioQuantity(row$) { + const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]'); + const firstRatioQuantity$ = row$.find('input[name$="[first_ratio_quantity]"]'); + if (firstRatioSelect$.val() === '') { + firstRatioQuantity$.val(''); + firstRatioQuantity$.attr('disabled', 'disabled'); + } else { + firstRatioQuantity$.removeAttr('disabled'); + } + } + + updateGroupOrderUnitSelect(row$) { + const supplierUnitSelect$ = row$.find('select[name$="[supplier_order_unit]"]'); + const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]'); + const groupOrderUnit$ = row$.find('select[name$="[group_order_unit]"]'); + + const unitsSelectedAbove = []; + const chosenSupplierUnitOption$ = supplierUnitSelect$.find(`option[value="${supplierUnitSelect$.val()}"]`); + unitsSelectedAbove.push({ key: chosenSupplierUnitOption$.val(), label: chosenSupplierUnitOption$.text() }); + + if (firstRatioSelect$.val() != '') { + const chosenFirstRatioOption$ = firstRatioSelect$.find(`option[value="${firstRatioSelect$.val()}"]`); + unitsSelectedAbove.push({ key: chosenFirstRatioOption$.val(), label: chosenFirstRatioOption$.text() }); + } + + const availableUnits = []; + for (const unitSelectedAbove of unitsSelectedAbove) { + availableUnits.push(unitSelectedAbove, ...this.availableUnits.filter(availableUnit => { + if (availableUnit.key === unitSelectedAbove.key) { + return false; + } + + const otherUnit = this.availableUnits.find(unit => unit.key === unitSelectedAbove.key); + return otherUnit !== undefined && otherUnit.baseUnit !== null && availableUnit.baseUnit === otherUnit.baseUnit; + })); + } + + this.updateUnitsInSelect(availableUnits, groupOrderUnit$); + } + + updateFirstUnitRatioSelect(row$) { + const supplierUnitSelect$ = row$.find('select[name$="[supplier_order_unit]"]'); + const firstRatioSelect$ = row$.find('select[name$="[first_ratio_unit]"]'); + const isUnitOrBaseUnitSelected = (unit, select$) => { + const code = select$.val(); + const selectedUnit = this.units[code]; + return unit.key !== code && (!unit.baseUnit || !selectedUnit || !selectedUnit.baseUnit || unit.baseUnit !== selectedUnit.baseUnit); + }; + + const remainingAvailableUnits = this.availableUnits.filter(unit => isUnitOrBaseUnitSelected(unit, supplierUnitSelect$)); + this.updateUnitsInSelect(remainingAvailableUnits, firstRatioSelect$, true); + } + + initializeArticlesList() { + this.table$.find('.articles-list .expander').click(function () { + const currentList$ = $(this).parents('.articles-list'); + currentList$.find('.expander').addClass('d-none'); + currentList$.find('.collapser').removeClass('d-none'); + currentList$.find('.list').removeClass('d-none'); + }); + + this.table$.find('.articles-list .collapser').click(function () { + const currentList$ = $(this).parents('.articles-list'); + currentList$.find('.expander').removeClass('d-none'); + currentList$.find('.collapser').addClass('d-none'); + currentList$.find('.list').addClass('d-none'); + }); + } + + updateUnitsInSelect(units, unitSelect$, includeBlank) { + const valueBeforeUpdate = unitSelect$.val(); + + unitSelect$.empty(); + if (includeBlank) { + unitSelect$.append($(``)); + } + for (const unit of units) { + unitSelect$.append($(``)); + } + + const initialValue = unitSelect$.attr('data-initial-value'); + if (initialValue) { + unitSelect$.val(initialValue); + unitSelect$.removeAttr('data-initial-value'); + } else { + if (unitSelect$.find(`option[value="${valueBeforeUpdate}"]`).length > 0) { + unitSelect$.val(valueBeforeUpdate); + } else { + unitSelect$.val(unitSelect$.find('option:first').val()); + } + } + + unitSelect$.trigger('change'); + + unitSelect$.parents('.control-group').find('.immutable_unit_label').remove(); + if (units.length === 1) { + unitSelect$.parents('.controls').hide(); + unitSelect$.parents('.control-group').append($(`
${units[0].label}
`)) + } else { + unitSelect$.parents('.controls').show(); + } + } + + +} diff --git a/app/assets/javascripts/receive-order-form.js b/app/assets/javascripts/receive-order-form.js new file mode 100644 index 000000000..320b54dcc --- /dev/null +++ b/app/assets/javascripts/receive-order-form.js @@ -0,0 +1,159 @@ +(function ( $ ) { + class ReceiveOrderForm { + constructor(receiveForm$, packageHelperIcon, newOrderArticlePath) { + this.receiveForm$ = receiveForm$; + this.packageHelperIcon = packageHelperIcon; + this.newOrderArticlePath = newOrderArticlePath; + $(document).on('change keyup', 'input[data-units-expected]', (e) => { + this.updateDelta(e.target); + }); + + $(document).on('touchclick', '#order_articles .unlocker', (e) => this.unlockReceiveInputField($(e.target))); + + $(document).on('click', '#set_all_to_zero', () => { + $('tbody input').each((_, input) => { + $(input).val(0); + this.updateDelta(input); + }); + }); + + $('input[data-units-expected]').each((_, field) => { + this.convertToBillingUnit($(field)); + this.updateDelta(field); + }); + + this.receiveForm$.submit(() => { + $('input[data-units-expected]').each((_, field) => { + this.convertFromBillingUnit($(field)); + }); + }); + + this.initAddArticle('#add_article'); + } + + convertFieldUnit(field$, fromUnit, toUnit) { + if (field$.is(':disabled')) { + return; + } + + const units = parseFloat(field$.val().replace(',', '.')); + if (isNaN(units)) { + return; + } + + const converter = field$.unitConversionField('getConverter'); + if (converter === undefined) { + return units; + } + return converter.getUnitRatio(units, fromUnit, toUnit); + } + + convertToBillingUnit(field$) { + const val = this.convertFieldUnit(field$, field$.data('supplier-order-unit'), field$.data('billing-unit')); + field$.val(val === undefined ? '' : round(val)); + } + + convertFromBillingUnit(field$) { + const convertedValue = this.convertFieldUnit(field$, field$.data('billing-unit'), field$.data('supplier-order-unit')); + if (convertedValue !== undefined) { + const hiddenReceivedField$ = $(``); + this.receiveForm$.append(hiddenReceivedField$); + } + } + + updateDelta(input) { + const units = $(input).val().replace(',', '.'); + const expected = $(input).data('units-expected'); + const delta = round(units-expected); + let html; + + if (units.replace(/\s/g,"")=="") { + // no value + html = ''; + } else if (isNaN(units)) { + html = ''; + } else if (delta == 0) { + // equal value + html = ''; + } else { + if (delta < 0) { + html = '- '+(-delta)+''; + } else /*if (units> expected)*/ { + html = '+ '+(delta)+''; + } + // show package icon only if the receive field has one + if ($(input).hasClass('package')) { + html += this.packageHelperIcon; + } + } + + $(input).closest('tr').find('.units_delta').html(html); + + // un-dim row when received is nonzero + $(input).closest('tr').toggleClass('unavailable', expected == 0 && html==''); + } + + + replace(id, newRow$) { + const oldRow$ = this.receiveForm$.find(`#order_article_${id}`); + const oldField$ = oldRow$.find('input.units_received') + const currentValue = oldField$.val(); + oldRow$.replaceWith(newRow$); + const newField$ = newRow$.find('input.units_received'); + newField$.val(currentValue); + newField$.unitConversionField(oldField$.unitConversionField('getConversionField')); + this.updateDelta(newField$); + } + + + initAddArticle(sel) { + $(sel).removeAttr('disabled').select2({ + placeholder: I18n.t('orders.receive.add_article'), + formatNoMatches: () => I18n.t('no_articles_available') + // TODO implement adding a new article, like in deliveries + }).on('change', (e) => { + var $input = $(e.target); + var selectedArticleId = $input.val(); + if(!selectedArticleId) { + return false; + } + + $.ajax({ + url: this.newOrderArticlePath, + type: 'post', + data: JSON.stringify({order_article: {article_version: {article_id: selectedArticleId}}}), + contentType: 'application/json; charset=UTF-8' + }); + + $input.val('').trigger('change'); + }); + $(sel).val('').trigger('change'); + } + + unlockReceiveInputField(unlockButton$) { + $('.units_received', unlockButton$.closest('tr')).prop('disabled', false).focus(); + unlockButton$.closest('.input-prepend').prop('title', I18n.t('orders.edit_amount.field_unlocked_title')); + unlockButton$.replaceWith(''); + } + } + + const receiveOrderFormsMap = new Map(); + + $.fn.receiveOrderForm = function (options, actionOptions) { + switch(options) { + case 'replace': { + const receiveOrderForm = receiveOrderFormsMap.get($(this)[0]); + receiveOrderForm.replace(actionOptions.id, actionOptions.newEntry); + break; + } + default: { + const receiveOrderForm = new ReceiveOrderForm($(this), options.packageHelperIcon, options.newOrderArticlePath); + receiveOrderFormsMap.set($(this)[0], receiveOrderForm); + break; + } + } + + return this; + }; + +}( jQuery )); diff --git a/app/assets/javascripts/unit-conversion-field.js b/app/assets/javascripts/unit-conversion-field.js new file mode 100644 index 000000000..303b9c108 --- /dev/null +++ b/app/assets/javascripts/unit-conversion-field.js @@ -0,0 +1,275 @@ + + + +(function ( $ ) { + + class UnitConversionField { + constructor(field$, units, popoverTemplate$, useTargetUnitForStep = true, ratios = undefined, supplierOrderUnit = undefined, defaultUnit = undefined, customUnit = undefined) { + this.field$ = field$; + this.popoverTemplate$ = popoverTemplate$; + this.popoverTemplate = this.popoverTemplate$[0].content.querySelector('.popover_contents'); + this.units = units; + this.useTargetUnitForStep = useTargetUnitForStep; + this.ratios = ratios; + this.supplierOrderUnit = supplierOrderUnit; + this.defaultUnit = defaultUnit; + this.customUnit = customUnit; + + this.loadArticleUnitRatios(); + this.unitSelectOptions = this.getUnitSelectOptions(); + + this.converter = new UnitsConverter(this.units, this.ratios, this.supplierOrderUnit); + + // if there's less then two options, don't even bother showing the popover: + this.disabled = this.unitSelectOptions.length < 2; + + this.opener$ = $(''); + this.opener$.attr('title', this.popoverTemplate.dataset.title); + this.field$.after(this.opener$); + + if (this.disabled) { + this.opener$.attr('disabled', 'disabled'); + this.opener$.attr('title', this.popoverTemplate.dataset.disabledTitle); + return; + } + + this.initializeOpenListener(); + } + + loadArticleUnitRatios() { + if (!this.ratios) { + this.ratios = []; + for (let i = 0; this.field$.data(`ratio-quantity-${i}`) !== undefined; i++) { + this.ratios.push({ + quantity: parseFloat(this.field$.data(`ratio-quantity-${i}`)), + unit: this.field$.data(`ratio-unit-${i}`), + }); + } + } + + if (this.supplierOrderUnit === undefined) { + this.supplierOrderUnit = this.field$.data('supplier-order-unit'); + } + if (this.customUnit === undefined) { + this.customUnit = this.field$.data('custom-unit'); + } + if (this.defaultUnit === undefined) { + this.defaultUnit = this.field$.data('default-unit'); + } + } + + initializeOpenListener() { + this.field$.popover({title: this.popoverTemplate.dataset.title, placement: 'bottom', trigger: 'manual'}); + + this.opener$.click((e) => { + e.preventDefault(); + e.stopPropagation(); + this.openPopover() + }); + + this.field$.on('shown.bs.popover', () => this.initializeConversionPopover(this.field$.next('.popover'))); + } + + openPopover() { + $(document).on('mousedown.unit-conversion-field', (e) => { + if ($(e.target).parents('.popover').length !== 0 || e.target === this.field$[0]) { + return; + } + + this.closePopover(); + }); + this.field$.popover('show'); + } + + closePopover() { + $(document).off('mousedown.unit-conversion-field'); + this.field$.off('change.unit-conversion-field'); + this.field$.popover('hide'); + } + + initializeConversionPopover(popover$) { + let showAgainHack = false; + if (!popover$.hasClass('wide')) { + popover$.addClass('wide'); + showAgainHack = true; + } + + const popoverContent$ = popover$.find('.popover-content'); + popoverContent$.empty(); + + const contents$ = $(document.importNode(this.popoverTemplate, true)); + popoverContent$.append(contents$); + + if (showAgainHack) { + this.openPopover(); + return; + } + + this.quantityInput$ = contents$.find('input.quantity'); + this.quantityInput$.val(String(this.field$.val()).replace(',', '.')); + this.quantityInput$ + .focus() + .select(); + 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 => $(``))) + let initialUnitSelectValue = this.defaultUnit; + if (initialUnitSelectValue === undefined) { + initialUnitSelectValue = this.unitSelectOptions[0].value; + } + this.unitSelect$.val(initialUnitSelectValue); + + this.previousUnitSelectValue = convertEmptyStringToUndefined(this.unitSelect$.val()); + + this.unitSelect$.change(() => this.onUnitSelectChanged()); + + // eslint-disable-next-line no-undef + mergeJQueryObjects([this.quantityInput$, this.unitSelect$]).change(() => this.prepareConversion()) + this.quantityInput$.keyup(() => this.quantityInput$.trigger('change')); + + 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()); + this.applyButton$.click(() => { + this.applyConversion(); + this.closePopover(); + }); + + this.onUnitSelectChanged(); + this.prepareConversion(); + } + + getUnitSelectOptions() { + const options = []; + const unit = this.units[this.supplierOrderUnit]; + options.push({ + value: this.supplierOrderUnit, + label: unit === undefined ? this.customUnit : this.getUnitLabel(unit) + }); + if (unit !== undefined) { + options.push(...this.getRelatedUnits(this.supplierOrderUnit)); + } + + + for (const ratio of this.ratios) { + options.push({ + value: ratio.unit, + label: this.getUnitLabel(this.units[ratio.unit]) + }); + + options.push(...this.getRelatedUnits(ratio.unit)); + } + + return options.sort((a, b) => a.label.localeCompare(b.label)); + } + + getUnitLabel(unit) { + let label = unit.name; + if (unit.symbol != null) { + label += ` (${unit.symbol})`; + } + + return label; + } + + 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() { + this.field$ + .val(this.getConversionResult()) + .trigger('change'); + } + + getQuantityInputValue() { + const val = parseFloat(this.quantityInput$.val().trim().replace(',', '.')); + if (isNaN(val)) { + return 0; + } + + return val; + } + + getTargetUnit() { + return this.defaultUnit === undefined ? this.supplierOrderUnit : this.defaultUnit; + } + + getConversionResult() { + const result = this.converter.getUnitRatio(this.getQuantityInputValue(), convertEmptyStringToUndefined(this.unitSelect$.val()), this.getTargetUnit()); + return Big(result).round(4).toNumber(); + } + + onUnitSelectChanged() { + const newValue = this.converter.getUnitRatio(this.getQuantityInputValue(), this.previousUnitSelectValue, convertEmptyStringToUndefined(this.unitSelect$.val())); + this.quantityInput$.val(newValue); + + const selectedUnit = convertEmptyStringToUndefined(this.unitSelect$.val()); + this.previousUnitSelectValue = selectedUnit; + + const step = this.useTargetUnitForStep ? this.converter.getUnitRatio(this.field$.attr('step'), this.getTargetUnit(), selectedUnit) : 0.001; + this.quantityInput$.attr('step', step); + } + + getRelatedUnits(unitId) { + return Object.entries(this.units) + .filter(([id, unit]) => unit.visible && unit.baseUnit !== null && unit.baseUnit === this.units[unitId].baseUnit && id !== unitId) + .map(([id, unit]) => ({ + value: id, + label: this.getUnitLabel(unit) + })); + } + } + + function convertEmptyStringToUndefined(str) { + if (str === '') { + return undefined; + } + + return str; + } + + const convertersMap = new Map(); + + $.fn.unitConversionField = function (optionsOrAction) { + const conversionField = convertersMap.get($(this)[0]); + switch(optionsOrAction) { + case 'getConversionField': + return conversionField; + case 'getConverter': + return conversionField === undefined ? undefined : conversionField.converter; + case 'destroy': + if (conversionField === undefined || conversionField.field$ === undefined) { + break; + } + conversionField.opener$.remove(); + convertersMap.delete($(this)[0]); + break; + default: { + const converter = new UnitConversionField($(this), optionsOrAction.units, optionsOrAction.popoverTemplate$, optionsOrAction.useTargetUnitForStep, optionsOrAction.ratios, optionsOrAction.supplierOrderUnit, optionsOrAction.defaultUnit, optionsOrAction.customUnit); + convertersMap.set($(this)[0], converter); + break; + } + } + + return this; + }; + + +}( jQuery )); diff --git a/app/assets/javascripts/units-converter.js b/app/assets/javascripts/units-converter.js new file mode 100644 index 000000000..40c65d62b --- /dev/null +++ b/app/assets/javascripts/units-converter.js @@ -0,0 +1,40 @@ +class UnitsConverter { + constructor(units, ratios, supplierOrderUnit) { + this.units = units; + this.ratios = ratios; + this.supplierOrderUnit = supplierOrderUnit; + } + + getUnitQuantity(unitId) { + if (unitId === this.supplierOrderUnit) { + return 1; + } + + const ratio = this.ratios.find(ratio => ratio.unit === unitId); + if (ratio !== undefined) { + return ratio.quantity; + } + + const unit = this.units[unitId]; + const relatedRatio = this.ratios.find(ratio => this.units[ratio.unit].baseUnit === unit.baseUnit); + if (relatedRatio !== undefined) { + const relatedUnit = this.units[relatedRatio.unit]; + return Big(relatedRatio.quantity).div(unit.conversionFactor).mul(relatedUnit.conversionFactor).toNumber(); + } + + const supplierOrderUnitConversionFactor = this.units[this.supplierOrderUnit].conversionFactor; + return Big(supplierOrderUnitConversionFactor).div(unit.conversionFactor).toNumber(); + } + + getUnitRatio(quantity, inputUnit, outputUnit) { + return Big(quantity).div(this.getUnitQuantity(inputUnit)).mul(this.getUnitQuantity(outputUnit)).toNumber(); + } + + isUnitSiConversible(unitId) { + const unit = this.units[unitId]; + if (unit === undefined) { + return false; + } + return !!unit.conversionFactor; + } +} diff --git a/app/assets/stylesheets/article.less b/app/assets/stylesheets/article.less new file mode 100644 index 000000000..a71d7e2f5 --- /dev/null +++ b/app/assets/stylesheets/article.less @@ -0,0 +1,38 @@ +.extra-unit-fields { + display: none; + position: absolute; + background: #fff; + border: 1px solid #888; + border-radius: 3px; + padding: 10px; + z-index: 999; + width:650px; + box-shadow: 10px 10px 22px 0px rgba(0,0,0,0.25); + + + &.show { + display: block; + } +} + +.extra-unit-fields-btn { + color: #000; +} + +.toggle-extra-units.default-values { + color: #333; + opacity: 0.65; +} + +.toggle-extra-units.show { + color: #333; + opacity: 1; +} + +.sync-table .control-group { + margin-bottom: 0; +} + +.sync-table .extra-unit-fields .control-group { + margin-bottom: 20px; +} diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less index 364dd8e25..6c0ff2b0b 100644 --- a/app/assets/stylesheets/bootstrap_and_overrides.css.less +++ b/app/assets/stylesheets/bootstrap_and_overrides.css.less @@ -1,5 +1,7 @@ @import "twitter/bootstrap/bootstrap"; @import "twitter/bootstrap/responsive"; +@import "group_order"; +@import "article"; @import "delta_input"; body { @@ -42,6 +44,10 @@ body { @articleUnusedColor: red; @articleUnavailColor: #999; @articleUpdatedColor: #468847; +@articleCustomUnitWarning: #ff8c00; + +// article units: +@unitUntranslatedColor: #999; // dim colors by this amount when the information is less important @nonessentialDim: 35%; @@ -279,6 +285,43 @@ tr.order-article:hover .article-info { display: block; } +tr.order-article { + .group-order-unit { + white-space: nowrap; + } + + + .used-unused, .used-unused-tolerance { + width: 70px; + text-wrap: nowrap; + } + + .group-order-input:not(.stock-order) { + .goa-quantity, .goa-tolerance { + width: 45px; + text-align: right; + } + } + + .group-order-input.stock-order { + width: 50px; + } +} + +.units_received_cell { + button { + margin-top: 0px; + height: 28px; + font-size: 10px; + line-height: 10px; + } + + input.units_received { + min-width: 45px; + height: 18px; + } +} + // ********* Articles @@ -319,6 +362,26 @@ td.symbol, th.symbol { .partused .symbol { color: tint(@articlePartusedColor, @nonessentialDim); } .unavailable .symbol { color: @articleUnavailColor; } +.article-form { + .icon-warning-sign { + margin-top: 8px; + margin-left: 10px; + color: @articleCustomUnitWarning; + } + + input[type=number]::-webkit-outer-spin-button, + input[type=number]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* Firefox */ + input[type=number] { + -moz-appearance: textfield; + } +} + + // hide symbols completely on small screens to save space @media (max-width: 768px) { .symbol { @@ -328,6 +391,11 @@ td.symbol, th.symbol { } } +// ********* Article units +tr.untranslated { + color: @unitUntranslatedColor; +} + // ********* Tweaks & fixes @@ -412,7 +480,8 @@ label { background-position: @align center; } input.package { - .package-image(right); + .package-image(90%); + background-size: 15px 15px; // disabled and readonly definitions though &[disabled], &[readonly] { background-color: @inputDisabledBackground; @@ -448,6 +517,16 @@ i.package.icon-only { margin: 0; } +// bootstrap 2 doesn't support differnt modal sizes -> let's provide our own modal-xl: +.modal.modal-xl { + width: 80vw; + max-width: 650px; + position: absolute; + left: 0; + right: 0; + margin: 0 auto; +} + // multiple-column layout in forms (landscape tablet and wider only) @media (min-width: 768px) { .form-horizontal .fold-line { @@ -547,4 +626,100 @@ span.negative_amout { details { cursor: pointer; -} \ No newline at end of file +} + +.form-horizontal .no-indent-left .control-group { + margin-bottom: 0; + .controls { + margin-left: 0; + } +} + +input:hover + .conversion-popover-opener, input:focus + .conversion-popover-opener, .conversion-popover-opener:hover, .conversion-popover-opener:focus { + opacity: 0.8; +} + +input.with-conversion-popover-opener { + padding-right: 20px; +} + +// bootstrap version 2 doesn't support some styles -> let's add makeshift ones manually for now: +.d-flex { + display: flex; +} + +.d-none { + display: none; +} + +.align-items-center { + align-items: center; +} + +.m-0 { + margin:0 !important; +} + +.ml-1 { + margin-left: 3px !important; +} + +.ml-2 { + margin-left: 6px !important; +} + +td.ml-1 > *:first-child { + margin-left: 3px !important; +} + + +.mr-1 { + margin-right: 3px !important; +} + +td.mr-1 > *:last-child { + margin-right: 3px; +} + +.mt-1 { + margin-top: 3px !important; +} + +.mb-1 { + margin-bottom: 3px !important; +} + +.text-decoration-none:hover { + text-decoration: none; +} + +// Wider popovers +.popover.wide { + max-width: 90vw; +} + +.gap-1 { + gap: .25rem; +} + +*[role="button"] { + cursor: pointer; +} + +.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/assets/stylesheets/delta_input.less b/app/assets/stylesheets/delta_input.less index c0afaf4c3..078157cdd 100644 --- a/app/assets/stylesheets/delta_input.less +++ b/app/assets/stylesheets/delta_input.less @@ -6,15 +6,28 @@ form.delta-input, .delta-input form { } .delta-input { - - .btn { - padding: 4px 0; + .btn.modify { + padding: 4px 8px; width: 24px; vertical-align: middle; font-size: 10px; + line-height: 14px; } + input[data-delta] { text-align: center; + height: 14px; + min-width: 45px; + + -moz-appearance: textfield; + + &::-webkit-inner-spin-button { + -webkit-appearance: none; + } + } + + .btn-ordering { + margin-top: 0px; } // handle error class outside of bootstrap controls diff --git a/app/assets/stylesheets/group_order.less b/app/assets/stylesheets/group_order.less new file mode 100644 index 000000000..3e68a346d --- /dev/null +++ b/app/assets/stylesheets/group_order.less @@ -0,0 +1,16 @@ +.group-order-input { + .btn-group .btn-ordering { + margin-top: 0; + } + + input.goa-quantity, input.goa-tolerance { + height: 14px; + border-radius: 0; + -moz-appearance: textfield; + + &::-webkit-inner-spin-button { + -webkit-appearance: none; + } + } +} + diff --git a/app/assets/stylesheets/main.sass b/app/assets/stylesheets/main.sass index 6a92e70c6..189d2d55b 100644 --- a/app/assets/stylesheets/main.sass +++ b/app/assets/stylesheets/main.sass @@ -25,7 +25,7 @@ body :color black :border :width 2px - :style solid + :style solid color: $main_red a, a:visited @@ -51,11 +51,11 @@ h1 h2 :font-size 1.4em :margin-top .5em - + h3 :font-size 1em :margin-top 1.5em - + input :color #2e2e2e @@ -121,14 +121,14 @@ option :border-top 1px dotted #ED0606 :color #2e2e2e - + // ******************************** - Logo - head -#header +#header :margin 0 :padding 0 -#logo +#logo background: $main_red :height 1.1em :width 8em @@ -150,45 +150,45 @@ option :font-weight bold :border-top :width 2px - :style dotted + :style dotted color: $main_red - + #logininfo :position absolute :top 3px :right 10px :font-size 1em - ul + ul :list-style none - li + li :margin 0 0 0 5px :float left - a + a :color #737272 :font-weight bold - a:hover + a:hover color: $main_red - + // ************************************* box structure -#main +#main :background #FFF :padding 0 :margin 0 15px 0 15px // ************************************* infobar -#infobar - :width 10% +#infobar + :width 10% :min-width 5em :float right :padding 2.6em 1em :margin 3em 0 0 0 :border-left 1px dotted #ED0606 - :font-size 1.2em + :font-size 1.2em h3 :color #ED0606 - ul + ul :list-style none - li + li :margin .3em 0 0 -3em // ************************************ embedded menu @@ -198,33 +198,33 @@ option :padding 0 10px 0px 5px :float left - ul + ul :list-style-type none :margin 0 0 0.2em 0 :padding 0 - li + li :border-bottom 1px solid #dedede :color #666 :margin 0.8em 0 0 0 - :font-weight bold - a:link, a:visited + :font-weight bold + a:link, a:visited :display block :padding 0.25em 1em :text-decoration none - :width 12em - a:hover, a:focus + :width 12em + a:hover, a:focus :background-color #e3e3e3 - ul + ul :margin 0 :padding 0 - li + li :border-top 1px solid #dedede :border-bottom none :margin 0 :font-weight normal - a:link, a:visited + a:link, a:visited :width 11.5em :padding 0 1em 0.1em 1.5em :font-weight normal @@ -233,9 +233,9 @@ option :position absolute :top 100px :right 1px - + // ************************************** content -#content +#content :padding .5em 0 2.5em 0 :margin 0 :background #FFF @@ -245,28 +245,28 @@ option /************************************ tables -table +table :border-collapse collapse // border2px solid #e3e3e3 :text-align left :width 100% :margin 0 - - thead th, tbody td, th, td - :padding 0.3em - thead tr + thead th, tbody td, th, td + :padding 0.3em + + thead tr :background-color #efefef th :color black tr.odd, tr.even - :border-top 1px solid #DDDDDD + :border-top 1px solid #DDDDDD tr.odd, tr.odd input :background-color #F6F6F6 tr.even :background-color #FBFBFB tr.unavailable, tr.unavailable a - :color grey + :color grey tr.unavailable a:hover :color #ED0606 tr.just_updated @@ -279,14 +279,14 @@ table color: green tr.failed color: red - + table.list //:border 2px solid #78b74e tr :border 1px solid #e3e3e3 tbody tr:hover :background-color #EEEEDD - + table tfoot tr :background-color #fff td @@ -297,12 +297,12 @@ tr.edit_inline td, span :padding 0.5em 0.2em -div.legend, div.legend table th +div.legend, div.legend table th :color grey :font-size .8em :background none -form table +form table :border none table.ordered_articles @@ -316,7 +316,7 @@ table.ordered_articles table tfoot :font-weight bold - + td.currency, td.actions :text-align right :padding-right 0.5em @@ -336,7 +336,7 @@ div.edit_form :padding 0 0.8em 0.8em 0.8em :margin 5px 0 :color black - + #edit_article, #edit_box, #ajax_box :position fixed :top 5em @@ -345,22 +345,22 @@ div.edit_form :background #FBFBFB :padding 3em :padding-top 1em - :border + :border :width 3px :style solid color: $main_red - + // ***************************************** other boxes */ // *********boxes in columns ****/ -div.box +div.box :border-left 2px solid #78b74e :padding-left 5px -div.single_column +div.single_column :width 100% -div.left_column +div.left_column :width 40% :float left @@ -376,22 +376,22 @@ div.right_column // *********** content of boxes ******/ -div.box_title +div.box_title :background #78b74e :padding 5px 10px - - h2, h2 a + + h2, h2 a :color #FFF :margin 0 h2 - :font-size 1.3em + :font-size 1.3em -div.column_content +div.column_content background: $boxContent :color black :padding 10px margin-bottom: 2em - h2 + h2 :color black :font-size 1.3em :margin 1em 0 0 0 @@ -407,16 +407,16 @@ div.column_content // * article show tr.current_price :background #cdee9e - + // **** maybe later for the very little spinner li.check div.spinner - :display block - :height 5px - :width 21px + :display block + :height 5px + :width 21px :background-image image-url('dots-white.gif') - :line-height 16px - :float left + :line-height 16px + :float left :margin-right 5px :background-position center center :background-repeat no-repeat @@ -425,12 +425,12 @@ li.check div.spinner // ************************************* the order page */ span.used, span.unused :font-weight bold -span.used +span.used :color #008000 span.unused :color #ed0606 span.total - :font-size 80% + :font-size 80% table#order :text-align center input @@ -513,7 +513,7 @@ tr.order-article:hover .article-info .timestamp :font-size 0.8em :color grey - + // *************** Clearing Order Page .. #editOrderNav a @@ -526,7 +526,7 @@ tr.order-article:hover .article-info :display inline :list-style none :margin-right 1em - + // *************** Tasks ... .accepted color: green @@ -534,7 +534,7 @@ tr.order-article:hover .article-info .done, .done a, .done .accepted color: grey font-weight: normal - + // ************** auto_complete ul.autocomplete .nick, .informal @@ -544,7 +544,7 @@ ul.autocomplete .informal color: grey margin-left: 1em - + // ******* to navigate easy to the next element, e.g. next order #element_navigation position: relative @@ -559,7 +559,7 @@ ul.autocomplete background-color: #fff text-align: center margin: 0 10px 10px 0 - + // *** wiki #wiki_content border-style: none diff --git a/app/controllers/api/v1/articles_controller.rb b/app/controllers/api/v1/articles_controller.rb new file mode 100644 index 000000000..34697b8da --- /dev/null +++ b/app/controllers/api/v1/articles_controller.rb @@ -0,0 +1,61 @@ +class Api::V1::ArticlesController < Api::V1::BaseController + skip_before_action :authenticate + + def index + supplier = Supplier.find_by_external_uuid!(index_params.fetch(:shared_supplier_uuid)) + + @articles = Article.with_latest_versions_and_categories.undeleted.where(supplier_id: supplier, type: nil) + @articles = @articles.where('article_versions.updated_at > ?', index_params[:updated_after].to_datetime) if index_params.include?(:updated_after) + @articles = @articles.where('article_versions.name LIKE ?', "%#{index_params[:name]}%") if index_params.include?(:name) + @articles = @articles.where(article_versions: { origin: index_params[:origin] }) if index_params.include?(:origin) + @articles = @articles.page(index_params[:page]).per(index_params.fetch(:per_page)) if index_params.include?(:page) + + data = @articles.map { |article| get_article_version_data(article) } + + render json: { articles: data, pagination: pagination_response, latest_update: get_latest_article_update(supplier) } + end + + protected + + def index_params + params.permit(:shared_supplier_uuid, :updated_after, :name, :origin, :page, :per_page) + end + + def get_article_version_data(article) + version_attributes = article.latest_article_version.attributes + version_attributes.delete_if { |key| key == 'id' || key.end_with?('_id') } + + version_attributes['article_unit_ratios'] = article.latest_article_version.article_unit_ratios.map do |ratio| + ratio_attributes = ratio.attributes + ratio_attributes.delete_if { |key| key == 'id' || key.end_with?('_id') } + end + + version_attributes + end + + def get_latest_article_update(supplier) + latest_update = Article + .with_latest_versions + .undeleted + .where(supplier_id: supplier, type: nil) + .order('article_versions.updated_at DESC') + .limit(1) + .first&.updated_at + latest_update&.utc + end + + def pagination_response + return nil unless index_params.include?(:page) + + current = @articles.current_page + total = @articles.total_pages + { + current_page: current, + previous_page: (current > 1 ? (current - 1) : nil), + next_page: (current == total ? nil : (current + 1)), + per_page: @articles.limit_value, + total_pages: total, + number: @articles.total_count + } + end +end diff --git a/app/controllers/api/v1/order_articles_controller.rb b/app/controllers/api/v1/order_articles_controller.rb index 6e7d220d2..b63a415c8 100644 --- a/app/controllers/api/v1/order_articles_controller.rb +++ b/app/controllers/api/v1/order_articles_controller.rb @@ -14,7 +14,7 @@ def show private def scope - OrderArticle.includes(:article_price, article: :supplier) + OrderArticle.includes(article_version: { article: :supplier }) end def search_scope diff --git a/app/controllers/api/v1/user/group_order_articles_controller.rb b/app/controllers/api/v1/user/group_order_articles_controller.rb index 4b65a61dc..5442f01bd 100644 --- a/app/controllers/api/v1/user/group_order_articles_controller.rb +++ b/app/controllers/api/v1/user/group_order_articles_controller.rb @@ -65,7 +65,7 @@ def max_per_page def scope GroupOrderArticle .joins(:group_order) - .includes(order_article: :article, group_order: :order) + .includes(order_article: :article_version, group_order: :order) .where(group_orders: { ordergroup_id: current_ordergroup.id }) end diff --git a/app/controllers/article_units_controller.rb b/app/controllers/article_units_controller.rb new file mode 100644 index 000000000..e9eef3dc5 --- /dev/null +++ b/app/controllers/article_units_controller.rb @@ -0,0 +1,63 @@ +class ArticleUnitsController < ApplicationController + before_action :authenticate_article_meta + before_action :load_available_units, only: %i[search create destroy] + + def index; end + + def search + @query = article_unit_params[:q].blank? ? nil : article_unit_params[:q].downcase + + existing_article_units = ArticleUnit.all.to_a + @article_units = @available_units + .to_h do |key, value| + [key, value.merge({ code: key, record: existing_article_units.find do |existing_unit| + existing_unit.unit == key + end })] + end + + unless @query.nil? + @article_units = @article_units.select do |_key, value| + (value[:name].downcase.include?(@query) || value[:symbol]&.downcase&.include?(@query)) && + (params[:only_recommended] == '0' || !value[:untranslated]) + end + end + + @article_units = @article_units + .sort { |a, b| sort_by_unit_name(@query, a, b) } + .map { |_key, value| value } + + @article_units = @article_units.take(100) unless @query.nil? + @article_units = @article_units.reject { |unit| unit[:record].nil? } if @query.nil? + end + + def create + @article_unit = ArticleUnit.create(unit: params[:unit]) + end + + def destroy + @article_unit = ArticleUnit.find(params[:id]) + @article_unit.destroy + end + + private + + def load_available_units + @available_units = ArticleUnitsLib.units + end + + def article_unit_params + params.permit(:q) + end + + def sort_by_unit_name(query, a_unit, b_unit) + a_name = a_unit[1][:name].downcase + b_name = b_unit[1][:name].downcase + + unless query.nil? + return -1 if a_name.starts_with?(query) && !b_name.starts_with?(query) + return 1 if !a_name.starts_with?(query) && b_name.starts_with?(query) + end + + a_name <=> b_name + end +end diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb index 232391cf0..642d063b9 100644 --- a/app/controllers/articles_controller.rb +++ b/app/controllers/articles_controller.rb @@ -1,32 +1,39 @@ class ArticlesController < ApplicationController before_action :authenticate_article_meta, :find_supplier + before_action :load_article, only: %i[edit update] + before_action :load_article_units, only: %i[edit update new create] + before_action :load_article_categories, only: %i[edit_all copy migrate_units update_all] + before_action :new_empty_article_ratio, + only: %i[edit edit_all migrate_units update new create parse_upload sync update_synchronized] + def index sort = if params['sort'] case params['sort'] - when 'name' then 'articles.name' - when 'unit' then 'articles.unit' + when 'name' then 'article_versions.name' + when 'unit' then 'article_versions.unit' when 'article_category' then 'article_categories.name' - when 'note' then 'articles.note' - when 'availability' then 'articles.availability' - when 'name_reverse' then 'articles.name DESC' - when 'unit_reverse' then 'articles.unit DESC' + when 'note' then 'article_versions.note' + when 'availability' then 'article_versions.availability' + when 'name_reverse' then 'article_versions.name DESC' + when 'unit_reverse' then 'article_versions.unit DESC' when 'article_category_reverse' then 'article_categories.name DESC' - when 'note_reverse' then 'articles.note DESC' - when 'availability_reverse' then 'articles.availability DESC' + when 'note_reverse' then 'article_versions.note DESC' + when 'availability_reverse' then 'article_versions.availability DESC' end else - 'article_categories.name, articles.name' + 'article_categories.name, article_versions.name' end - @articles = Article.undeleted.where(supplier_id: @supplier, type: nil).includes(:article_category).order(sort) + @articles = Article.with_latest_versions_and_categories.order(sort).undeleted.where(supplier_id: @supplier, + type: nil) if request.format.csv? send_data ArticlesCsv.new(@articles, encoding: 'utf-8').to_csv, filename: 'articles.csv', type: 'text/csv' return end - @articles = @articles.where('articles.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil? + @articles = @articles.where('article_versions.name LIKE ?', "%#{params[:query]}%") unless params[:query].nil? @articles = @articles.page(params[:page]).per(@per_page) @@ -37,37 +44,49 @@ def index end def new - @article = @supplier.articles.build(tax: FoodsoftConfig[:tax_default]) + @article = @supplier.articles.build + @article.latest_article_version = @article.article_versions.build(tax: FoodsoftConfig[:tax_default]) render layout: false end def copy - @article = @supplier.articles.find(params[:article_id]).dup + article = @supplier.articles.find(params[:article_id]) + @article = article.duplicate_including_latest_version_and_ratios + load_article_units(@article.current_article_units) render layout: false end def edit - @article = Article.find(params[:id]) render action: 'new', layout: false end def create - @article = Article.new(params[:article]) - if @article.valid? && @article.save + valid = false + Article.transaction do + @article = Article.create(supplier_id: @supplier.id) + @article.attributes = { latest_article_version_attributes: params[:article_version] } + raise ActiveRecord::Rollback unless @article.valid? + + valid = @article.save + end + + if valid render layout: false else + load_article_units(@article.current_article_units) render action: 'new', layout: false end end # Updates one Article and highlights the line if succeded def update - @article = Article.find(params[:id]) - - if @article.update(params[:article]) - render layout: false - else - render action: 'new', layout: false + Article.transaction do + if @article.update(latest_article_version_attributes: params[:article_version]) + render layout: false + else + Rails.logger.info @article.errors.to_yaml.to_s + render action: 'new', layout: false + end end end @@ -81,6 +100,85 @@ def destroy # Renders a form for editing all articles from a supplier def edit_all @articles = @supplier.articles.undeleted + + load_article_units + end + + def prepare_units_migration; end + + def migrate_units + build_article_migration_samples + end + + def complete_units_migration + @invalid_articles = [] + @samples = [] + + Article.transaction do + params[:samples].values.each do |sample| + next unless sample[:apply_migration] == '1' + + original_unit = nil + articles = Article.with_latest_versions_and_categories + .includes(latest_article_version: [:article_unit_ratios]) + .find(sample[:article_ids]) + articles.each do |article| + latest_article_version = article.latest_article_version + original_unit = latest_article_version.unit + next if latest_article_version.article_unit_ratios.length > 1 || + latest_article_version.billing_unit != latest_article_version.group_order_unit || + latest_article_version.price_unit != latest_article_version.group_order_unit + + article_version_params = sample.slice(:supplier_order_unit, :group_order_granularity, :group_order_unit) + article_version_params[:unit] = nil + article_version_params[:billing_unit] = article_version_params[:group_order_unit] + article_version_params[:price_unit] = article_version_params[:group_order_unit] + article_version_params[:article_unit_ratios_attributes] = {} + if sample[:first_ratio_unit].present? + article_version_params[:article_unit_ratios_attributes]['1'] = { + id: latest_article_version.article_unit_ratios.first&.id, + sort: 1, + quantity: sample[:first_ratio_quantity], + unit: sample[:first_ratio_unit] + } + end + article_version_params[:id] = latest_article_version.id + @invalid_articles << article unless article.update(latest_article_version_attributes: article_version_params) + end + + errors = articles.find { |a| !a.errors.nil? }&.errors + @samples << { + unit: original_unit, + conversion_result: sample + .except(:article_ids, :first_ratio_quantity, :first_ratio_unit) + .merge( + first_ratio: { + quantity: sample[:first_ratio_quantity], + unit: sample[:first_ratio_unit] + } + ), + articles: articles, + errors: errors, + error: errors.present? + } + end + @supplier.update_attribute(:unit_migration_completed, Time.now) + raise ActiveRecord::Rollback unless @invalid_articles.empty? + end + + if @invalid_articles.empty? + redirect_to supplier_articles_path(@supplier), + notice: I18n.t('articles.controller.complete_units_migration.notice') + else + additional_units = @samples.map do |sample| + [sample[:conversion_result][:supplier_order_unit], sample[:conversion_result][:group_order_unit], + sample[:conversion_result][:first_ratio]&.dig(:unit)] + end.flatten.uniq.compact + load_article_units(additional_units) + + flash.now.alert = I18n.t('articles.controller.error_invalid') + render :migrate_units + end end # Updates all article of specific supplier @@ -90,13 +188,19 @@ def update_all Article.transaction do if params[:articles].present? # Update other article attributes... - @articles = Article.find(params[:articles].keys) + @articles = Article.with_latest_versions_and_categories + .includes(latest_article_version: [:article_unit_ratios]) + .find(params[:articles].keys) @articles.each do |article| - unless article.update(params[:articles][article.id.to_s]) + article_version_params = params[:articles][article.id.to_s] + article_version_params['id'] = article.latest_article_version.id + unless article.update(latest_article_version_attributes: article_version_params) invalid_articles ||= true # Remember that there are validation errors end end + @supplier.update_attribute(:unit_migration_completed, Time.now) if params[:complete_migration] + raise ActiveRecord::Rollback if invalid_articles # Rollback all changes end end @@ -115,7 +219,9 @@ def update_all def update_selected raise I18n.t('articles.controller.error_nosel') if params[:selected_articles].nil? - articles = Article.find(params[:selected_articles]) + articles = Article.with_latest_versions_and_categories + .includes(latest_article_version: [:article_unit_ratios]) + .find(params[:selected_articles]) Article.transaction do case params[:selected_action] when 'destroy' @@ -148,11 +254,15 @@ def parse_upload options = { filename: uploaded_file.original_filename } options[:outlist_absent] = (params[:articles]['outlist_absent'] == '1') options[:convert_units] = (params[:articles]['convert_units'] == '1') - @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_from_file uploaded_file.tempfile, - options + @updated_article_pairs, @outlisted_articles, @new_articles, import_data = @supplier.sync_from_file(uploaded_file.tempfile, + options) + + @articles = @updated_article_pairs.pluck(0) + @new_articles + load_article_units + if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? redirect_to supplier_articles_path(@supplier), - notice: I18n.t('articles.controller.parse_upload.notice') + notice: I18n.t('articles.controller.parse_upload.notice', count: import_data[:articles].length) end @ignored_article_count = 0 rescue StandardError => e @@ -162,24 +272,28 @@ def parse_upload # sync all articles with the external database # renders a form with articles, which should be updated def sync - # check if there is an shared_supplier - unless @supplier.shared_supplier - redirect_to supplier_articles_url(@supplier), - alert: I18n.t('articles.controller.sync.shared_alert', supplier: @supplier.name) - end - # sync articles against external database - @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_all - return unless @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? - - redirect_to supplier_articles_path(@supplier), notice: I18n.t('articles.controller.sync.notice') + @updated_article_pairs, @outlisted_articles, @new_articles, import_data = @supplier.sync_from_remote + redirect_to(supplier_articles_path(@supplier), notice: I18n.t('articles.controller.parse_upload.notice', count: import_data[:articles].length)) if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? + @ignored_article_count = 0 + load_article_units((@new_articles + @updated_article_pairs.map(&:first)).map(&:current_article_units).flatten.uniq) + rescue StandardError => e + redirect_to upload_supplier_articles_path(@supplier), alert: I18n.t('errors.general_msg', msg: e.message) end # Updates, deletes articles when upload or sync form is submitted def update_synchronized - @outlisted_articles = Article.find(params[:outlisted_articles].try(:keys) || []) - @updated_articles = Article.find(params[:articles].try(:keys) || []) - @updated_articles.map { |a| a.assign_attributes(params[:articles][a.id.to_s]) } - @new_articles = (params[:new_articles] || []).map { |a| @supplier.articles.build(a) } + @outlisted_articles = Article.includes(:latest_article_version).where(article_versions: { id: params[:outlisted_articles]&.values || [] }) + @updated_articles = Article.includes(:latest_article_version).where(article_versions: { id: params[:articles]&.values&.map do |v| + v[:id] + end || [] }) + @new_articles = (params[:new_articles]&.values || []).map do |a| + article = @supplier.articles.build + article_version = article.article_versions.build(a) + article.article_versions << article_version + article.latest_article_version = article_version + article_version.article = article + article + end has_error = false Article.transaction do @@ -191,7 +305,14 @@ def update_synchronized has_error = true end # Update articles - @updated_articles.each { |a| a.save or has_error = true } + @updated_articles.each_with_index do |a, index| + current_params = params[:articles][index.to_s] + current_params.delete(:id) + + a.latest_article_version.article_unit_ratios.clear + a.latest_article_version.assign_attributes(current_params) + a.save + end or has_error = true # Add new articles @new_articles.each { |a| a.save or has_error = true } @@ -199,6 +320,7 @@ def update_synchronized end if has_error + load_article_units((@new_articles + @updated_articles).map(&:current_article_units).flatten.uniq) @updated_article_pairs = @updated_articles.map do |article| orig_article = Article.find(article.id) [article, orig_article.unequal_attributes(article)] @@ -210,35 +332,80 @@ def update_synchronized end end - # renders a view to import articles in local database - # - def shared - # build array of keywords, required for ransack _all suffix - q = params.fetch(:q, {}) - q[:name_cont_all] = params.fetch(:name_cont_all_joined, '').split(' ') - search = @supplier.shared_supplier.shared_articles.ransack(q) - @articles = search.result.page(params[:page]).per(10) - render layout: false - end + private - # fills a form whith values of the selected shared_article - # when the direct parameter is set and the article is valid, it is imported directly - def import - @article = SharedArticle.find(params[:shared_article_id]).build_new_article(@supplier) - @article.article_category_id = params[:article_category_id] if params[:article_category_id].present? - if params[:direct] && params[:article_category_id].present? && @article.valid? && @article.save - render action: 'create', layout: false - else - render action: 'new', layout: false + def build_article_migration_samples + articles = @supplier.articles.with_latest_versions_and_categories.undeleted.includes(latest_article_version: [:article_unit_ratios]) + samples_hash = {} + articles.each do |article| + article_version = article.latest_article_version + quantity = 1 + ratios = article_version.article_unit_ratios + + next if ratios.length > 1 || + article_version.billing_unit != article_version.group_order_unit || + article_version.price_unit != article_version.group_order_unit + + quantity = ratios[0].quantity if ratios.length == 1 && ratios[0].quantity != 1 && ratios[0].unit == 'XPP' + + samples_hash[article_version.unit] = {} if samples_hash[article_version.unit].nil? + samples_hash[article_version.unit][quantity] = [] if samples_hash[article_version.unit][quantity].nil? + samples_hash[article_version.unit][quantity] << article + end + @samples = samples_hash.map do |unit, quantities_hash| + quantities_hash.map do |quantity, sample_articles| + conversion_result = ArticleUnitsLib.convert_old_unit(unit, quantity) + { unit: unit, quantity: quantity, articles: sample_articles, conversion_result: conversion_result } + end end + @samples = @samples.flatten + .reject { |sample| sample[:conversion_result].nil? } + + additional_units = @samples.map do |sample| + [sample[:conversion_result][:supplier_order_unit], sample[:conversion_result][:group_order_unit], + sample[:conversion_result][:first_ratio]&.dig(:unit)] + end.flatten.uniq.compact + load_article_units(additional_units) end - private + def load_article + @article = Article + .with_latest_versions_and_categories + .includes(latest_article_version: [:article_unit_ratios]) + .find(params[:id]) + end + + def load_article_units(additional_units = []) + additional_units = if !@article.nil? + @article.current_article_units + elsif !@articles.nil? + @articles.map(&:current_article_units) + .flatten + .uniq + else + additional_units + end + + @article_units = ArticleUnit.as_options(additional_units: additional_units) + @all_units = ArticleUnit.as_hash(additional_units: additional_units) + end + + def load_article_categories + @article_categories = ArticleCategory.all + end + + def new_empty_article_ratio + @empty_article_unit_ratio = ArticleUnitRatio.new + @empty_article_unit_ratio.article_version = @article.latest_article_version unless @article.nil? + @empty_article_unit_ratio.sort = -1 + end # @return [Number] Number of articles not taken into account when syncing (having no number) def ignored_article_count if action_name == 'sync' || params[:from_action] == 'sync' - @ignored_article_count ||= @supplier.articles.undeleted.where(order_number: [nil, '']).count + @ignored_article_count ||= @supplier.articles.includes(:latest_article_version).undeleted.where(article_versions: { order_number: [ + nil, '' + ] }).count else 0 end diff --git a/app/controllers/deliveries_controller.rb b/app/controllers/deliveries_controller.rb index 15900022c..0ef9e0ab8 100644 --- a/app/controllers/deliveries_controller.rb +++ b/app/controllers/deliveries_controller.rb @@ -7,7 +7,7 @@ def index def show @delivery = Delivery.find(params[:id]) - @stock_changes = @delivery.stock_changes.includes(:stock_article).order('articles.name ASC') + @stock_changes = @delivery.stock_changes.includes(stock_article: :latest_article_version).order('article_versions.name ASC') end def new diff --git a/app/controllers/finance/balancing_controller.rb b/app/controllers/finance/balancing_controller.rb index 2f67c3714..3976e235c 100644 --- a/app/controllers/finance/balancing_controller.rb +++ b/app/controllers/finance/balancing_controller.rb @@ -8,19 +8,19 @@ def new flash.now.alert = t('.alert') if @order.closed? @comments = @order.comments - @articles = @order.order_articles.ordered_or_member.includes(:article, :article_price, + @articles = @order.order_articles.ordered_or_member.includes(article_version: :article, group_order_articles: { group_order: :ordergroup }) sort_param = params['sort'] || 'name' @articles = case sort_param when 'name' - @articles.order('articles.name ASC') + @articles.order('article_versions.name ASC') when 'name_reverse' - @articles.order('articles.name DESC') + @articles.order('article_versions.name DESC') when 'order_number' - @articles.order('articles.order_number ASC') + @articles.order('article_versions.order_number ASC') when 'order_number_reverse' - @articles.order('articles.order_number DESC') + @articles.order('article_versions.order_number DESC') else @articles end diff --git a/app/controllers/group_order_articles_controller.rb b/app/controllers/group_order_articles_controller.rb index c9273b79a..286420d84 100644 --- a/app/controllers/group_order_articles_controller.rb +++ b/app/controllers/group_order_articles_controller.rb @@ -65,7 +65,7 @@ def update_summaries(group_order_article) # Update the price attribute of new GroupOrder group_order_article.group_order.update_price! # Update units_to_order of order_article - group_order_article.order_article.update_results! if group_order_article.order_article.article.is_a?(StockArticle) + group_order_article.order_article.update_results! if group_order_article.order_article.article_version.is_a?(StockArticle) end def find_group_order_article diff --git a/app/controllers/order_articles_controller.rb b/app/controllers/order_articles_controller.rb index 433e07bb9..8751021f2 100644 --- a/app/controllers/order_articles_controller.rb +++ b/app/controllers/order_articles_controller.rb @@ -2,6 +2,9 @@ class OrderArticlesController < ApplicationController before_action :fetch_order, except: :destroy before_action :authenticate_finance_or_invoices, except: %i[new create] before_action :authenticate_finance_orders_or_pickup, except: %i[edit update destroy] + before_action :load_order_article, only: %i[edit update] + before_action :load_article_units, only: %i[edit update] + before_action :new_empty_article_ratio, only: %i[edit update] layout false # We only use this controller to serve js snippets, no need for layout rendering @@ -9,15 +12,13 @@ def new @order_article = @order.order_articles.build(params[:order_article]) end - def edit - @order_article = OrderArticle.find(params[:id]) - end + def edit; end def create # The article may be ordered with zero units - in that case do not complain. # If order_article is ordered and a new order_article is created, an error message will be # given mentioning that the article already exists, which is desired. - @order_article = @order.order_articles.where(article_id: params[:order_article][:article_id]).first + @order_article = @order.order_articles.joins(:article_version).where(id: params[:order_article][:article_version_id]).first @order_article = @order.order_articles.build(params[:order_article]) unless @order_article && @order_article.units_to_order == 0 @order_article.save! rescue StandardError @@ -25,12 +26,14 @@ def create end def update - @order_article = OrderArticle.find(params[:id]) - begin - @order_article.update_article_and_price!(params[:order_article], params[:article], params[:article_price]) - rescue StandardError - render action: :edit - end + # begin + version_params = params.require(:article_version).permit(:id, :unit, :supplier_order_unit, :minimum_order_quantity, + :billing_unit, :group_order_granularity, :group_order_unit, :price, :price_unit, :tax, :deposit, article_unit_ratios_attributes: %i[id sort quantity unit _destroy]) + @order_article.update_handling_versioning!(params[:order_article], version_params) + # TODO-article-version + # rescue + # render action: :edit + # end end def destroy @@ -59,4 +62,20 @@ def authenticate_finance_orders_or_pickup deny_access end + + def load_order_article + @order_article = OrderArticle.includes(article_version: :article_unit_ratios).find(params[:id]) + end + + def load_article_units + additional_units = @order_article&.article_version&.article&.current_article_units || [] + @article_units = ArticleUnit.as_options(additional_units: additional_units) + @all_units = ArticleUnit.as_hash(additional_units: additional_units) + end + + def new_empty_article_ratio + @empty_article_unit_ratio = ArticleUnitRatio.new + @empty_article_unit_ratio.article_version = @order_article.price + @empty_article_unit_ratio.sort = -1 + end end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index bc2d91954..e8598393d 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -95,7 +95,7 @@ def create # Update an existing order. def update @order = Order.find params[:id] - if @order.update(params[:order].merge(updated_by: current_user)) + if @order.update params[:order].merge(updated_by: current_user) flash[:notice] = I18n.t('orders.update.notice') redirect_to action: 'show', id: @order else @@ -145,7 +145,7 @@ def receive redirect_to receive_order_path(@order) end else - @order_articles = @order.order_articles.ordered_or_member.includes(:article).order('articles.order_number, articles.name') + @order_articles = @order.order_articles.ordered_or_member.includes(:article_version).order('article_versions.order_number, article_versions.name') end end @@ -186,8 +186,10 @@ def update_order_amounts if oa.units_received_changed? counts[0] += 1 if oa.units_received.present? - cunits[0] += oa.units_received * oa.article.unit_quantity - oacounts = oa.redistribute oa.units_received * oa.price.unit_quantity, rest_to + units_received = oa.article_version.convert_quantity(oa.units_received, + oa.article_version.supplier_order_unit, oa.article_version.group_order_unit) + cunits[0] += units_received + oacounts = oa.redistribute units_received, rest_to oacounts.each_with_index do |c, i| cunits[i + 1] += c counts[i + 1] += 1 if c > 0 @@ -213,6 +215,6 @@ def update_order_amounts end def remove_empty_article - params[:order][:article_ids].compact_blank! if params[:order] && params[:order][:article_ids] + params[:order][:article_ids].reject!(&:blank?) if params[:order] && params[:order][:article_ids] end end diff --git a/app/controllers/stock_takings_controller.rb b/app/controllers/stock_takings_controller.rb index e12af6f91..d61488a07 100644 --- a/app/controllers/stock_takings_controller.rb +++ b/app/controllers/stock_takings_controller.rb @@ -7,7 +7,9 @@ def index def new @stock_taking = StockTaking.new - StockArticle.undeleted.each { |a| @stock_taking.stock_changes.build(stock_article: a) } + StockArticle.with_latest_versions_and_categories.undeleted.each do |a| + @stock_taking.stock_changes.build(stock_article: a) + end end def new_on_stock_article_create # See publish/subscribe design pattern in /doc. diff --git a/app/controllers/stockit_controller.rb b/app/controllers/stockit_controller.rb index 8f9b3b3dd..e9e9be0d1 100644 --- a/app/controllers/stockit_controller.rb +++ b/app/controllers/stockit_controller.rb @@ -1,23 +1,24 @@ class StockitController < ApplicationController + before_action :new_empty_article_ratio, only: %i[edit update new create derive copy] + before_action :load_article, + only: %i[index_on_stock_article_create index_on_stock_article_update show edit update show_on_stock_article_update + destroy] + before_action :load_article_units, only: %i[edit update new create derive copy] + before_action :prepare_params_for_create_update, only: %i[create update] + def index - @stock_articles = StockArticle.undeleted.includes(:supplier, :article_category) - .order('suppliers.name, article_categories.name, articles.name') + @stock_articles = StockArticle.with_latest_versions_and_categories.joins(:supplier).order('suppliers.name, article_categories.name, article_versions.name').undeleted end def index_on_stock_article_create # See publish/subscribe design pattern in /doc. - @stock_article = StockArticle.find(params[:id]) - render layout: false end def index_on_stock_article_update # See publish/subscribe design pattern in /doc. - @stock_article = StockArticle.find(params[:id]) - render layout: false end def show - @stock_article = StockArticle.find(params[:id]) @stock_changes = @stock_article.stock_changes.order('stock_changes.created_at DESC') end @@ -25,54 +26,58 @@ def show # (1) start from blank or use params def new @stock_article = StockArticle.new(params[:stock_article]) + @stock_article.latest_article_version = ArticleVersion.new render layout: false end # (2) StockArticle as template def copy - @stock_article = StockArticle.find(params[:stock_article_id]).dup + stock_article = StockArticle.find(params[:stock_article_id]) + @stock_article = stock_article.dup + @stock_article.latest_article_version = stock_article.latest_article_version.duplicate_including_article_unit_ratios render layout: false end # (3) non-stock Article as template def derive - @stock_article = Article.find(params[:old_article_id]).becomes(StockArticle).dup + article = Article.find(params[:old_article_id]) + @stock_article = article.becomes(StockArticle).dup + @stock_article.latest_article_version = article.latest_article_version.duplicate_including_article_unit_ratios render layout: false end def edit - @stock_article = StockArticle.find(params[:id]) - render layout: false end def create - @stock_article = StockArticle.new({ quantity: 0 }.merge(params[:stock_article])) - @stock_article.save! + StockArticle.transaction do + @stock_article = StockArticle.create(quantity: 0, supplier_id: @supplier_id) + @stock_article.attributes = { latest_article_version_attributes: params[:article_version] } + @stock_article.save + end render layout: false rescue ActiveRecord::RecordInvalid render action: 'new', layout: false end def update - @stock_article = StockArticle.find(params[:id]) - @stock_article.update!(params[:stock_article]) + article_version_attributes = params[:article_version] + @stock_article.update!(supplier_id: @supplier_id, + latest_article_version_attributes: article_version_attributes) render layout: false rescue ActiveRecord::RecordInvalid render action: 'edit', layout: false end def show_on_stock_article_update # See publish/subscribe design pattern in /doc. - @stock_article = StockArticle.find(params[:id]) - render layout: false end def destroy - @stock_article = StockArticle.find(params[:id]) @stock_article.mark_as_deleted render layout: false rescue StandardError => e @@ -85,4 +90,32 @@ def articles_search @articles = Article.not_in_stock.limit(8).where('name LIKE ?', "%#{params[:term]}%") render json: @articles.map(&:name) end + + private + + def load_article + @stock_article = StockArticle.find(params[:id]) + end + + def load_article_units + additional_units = @stock_article&.current_article_units || [] + @article_units = ArticleUnit.as_options(additional_units: additional_units) + @all_units = ArticleUnit.as_hash(additional_units: additional_units) + end + + def new_empty_article_ratio + @empty_article_unit_ratio = ArticleUnitRatio.new + @empty_article_unit_ratio.article_version = @article.latest_article_version unless @article.nil? + @empty_article_unit_ratio.sort = -1 + end + + def prepare_params_for_create_update + @supplier_id = params[:article_version][:article][:supplier_id] + params[:article_version].delete :article + + # Stock article form doesn't have some of the unit fields -> set them to supplier_order_unit: + params[:article_version][:group_order_unit] = params[:article_version][:supplier_order_unit] + params[:article_version][:billing_unit] = params[:article_version][:supplier_order_unit] + params[:article_version][:price_unit] = params[:article_version][:supplier_order_unit] + end end diff --git a/app/controllers/supplier_shares_controller.rb b/app/controllers/supplier_shares_controller.rb new file mode 100644 index 000000000..6305f3f1d --- /dev/null +++ b/app/controllers/supplier_shares_controller.rb @@ -0,0 +1,17 @@ +class SupplierSharesController < ApplicationController + before_action :authenticate_suppliers + + def create + @supplier = Supplier.find(params[:supplier_id]) + @supplier.update_attribute(:external_uuid, SecureRandom.uuid) + + render 'update' + end + + def destroy + @supplier = Supplier.find(params[:supplier_id]) + @supplier.update_attribute(:external_uuid, nil) + + render 'update' + end +end diff --git a/app/controllers/suppliers_controller.rb b/app/controllers/suppliers_controller.rb index 1f1e055d7..599d83d6a 100644 --- a/app/controllers/suppliers_controller.rb +++ b/app/controllers/suppliers_controller.rb @@ -1,3 +1,5 @@ +require 'ostruct' + class SuppliersController < ApplicationController before_action :authenticate_suppliers, except: %i[index list] helper :deliveries @@ -14,14 +16,8 @@ def show end # new supplier - # if shared_supplier_id is given, the new supplier will filled whith its attributes def new - if params[:shared_supplier_id] - shared_supplier = SharedSupplier.find(params[:shared_supplier_id]) - @supplier = shared_supplier.suppliers.new(shared_supplier.autofill_attributes) - else - @supplier = Supplier.new - end + @supplier = Supplier.new end def edit @@ -31,6 +27,8 @@ def edit def create @supplier = Supplier.new(supplier_params) @supplier.supplier_category ||= SupplierCategory.first + @supplier.unit_migration_completed = Time.now + if @supplier.save flash[:notice] = I18n.t('suppliers.create.notice') redirect_to suppliers_path @@ -59,18 +57,29 @@ def destroy redirect_to @supplier end - # gives a list with all available shared_suppliers - def shared_suppliers - @shared_suppliers = SharedSupplier.all + def remote_articles + @supplier = Supplier.find(remote_articles_params.fetch(:supplier_id)) + search_params = {} + search_params[:name] = params.fetch(:name).split if params.include?(:name) + search_params[:origin] = params.fetch(:origin) if params.include?(:origin) + search_params[:page] = params.fetch(:page, 1) + search_params[:per_page] = @per_page + data = @supplier.read_from_remote(search_params) + @articles = data[:articles] + @pagination = OpenStruct.new(data[:pagination]) end private + def remote_articles_params + params.permit(:supplier_id, :name, :origin) + end + def supplier_params params .require(:supplier) .permit(:name, :address, :phone, :phone2, :fax, :email, :url, :contact_person, :customer_number, :iban, :custom_fields, :delivery_days, :order_howto, :note, :supplier_category_id, - :shared_supplier_id, :min_order_quantity, :shared_sync_method) + :min_order_quantity, :shared_sync_method, :supplier_remote_source) end end diff --git a/app/documents/order_by_articles.rb b/app/documents/order_by_articles.rb index b1a68a115..a19bfc932 100644 --- a/app/documents/order_by_articles.rb +++ b/app/documents/order_by_articles.rb @@ -10,6 +10,7 @@ def title def body each_order_article do |order_article| + article_version = order_article.article_version dimrows = [] rows = [[ GroupOrder.human_attribute_name(:ordergroup), @@ -21,13 +22,16 @@ def body each_group_order_article_for_order_article(order_article) do |goa| dimrows << rows.length if goa.result == 0 rows << [goa.group_order.ordergroup_name, - group_order_article_quantity_with_tolerance(goa), - goa.result, + billing_quantity_with_tolerance(goa), + number_with_precision(article_version.convert_quantity(goa.result, article_version.group_order_unit, + article_version.billing_unit)), number_to_currency(goa.total_price)] end next unless rows.length > 1 - name = "#{order_article.article.name} (#{order_article.article.unit} | #{order_article.price.unit_quantity} | #{number_to_currency(order_article.price.fc_price)})" + name = "#{article_version.name}, #{format_billing_unit_with_ratios(article_version)}, #{number_to_currency(article_version.convert_quantity( + article_version.fc_price, article_version.billing_unit, article_version.supplier_order_unit + ))}" name += " #{order_article.order.name}" if @options[:show_supplier] nice_table name, rows, dimrows do |table| table.column(0).width = bounds.width / 2 diff --git a/app/documents/order_by_groups.rb b/app/documents/order_by_groups.rb index e5a72c350..7a19a9dc9 100644 --- a/app/documents/order_by_groups.rb +++ b/app/documents/order_by_groups.rb @@ -23,11 +23,11 @@ def body each_group_order_article_for_ordergroup(oa_id) do |goa| dimrows << rows.length if goa.result == 0 - rows << [goa.order_article.article.name, + rows << [goa.order_article.article_version.name, goa.group_order.order.name, - group_order_article_quantity_with_tolerance(goa), - group_order_article_result(goa), - order_article_price_per_unit(goa.order_article), + billing_quantity_with_tolerance(goa), + billing_article_result(goa), + price_per_billing_unit(goa), number_to_currency(goa.total_price)] end next unless rows.length > 1 diff --git a/app/documents/order_fax.rb b/app/documents/order_fax.rb index e881c93f1..a1dd55097 100644 --- a/app/documents/order_fax.rb +++ b/app/documents/order_fax.rb @@ -1,4 +1,7 @@ class OrderFax < OrderPdf + include ArticlesHelper + include OrdersHelper + BATCH_SIZE = 250 def filename @@ -10,9 +13,20 @@ def title end def body - contact = FoodsoftConfig[:contact].symbolize_keys + from_paragraph + + recipient_paragraph + + articles_paragraph + rescue StandardError => e + Rails.logger.info e.backtrace + raise # always reraise + end - # From paragraph + private + + def from_paragraph + contact = FoodsoftConfig[:contact].symbolize_keys bounding_box [margin_box.right - 200, margin_box.top], width: 200 do text FoodsoftConfig[:name], size: fontsize(9), align: :right move_down 5 @@ -34,8 +48,9 @@ def body align: :right end end + end - # Recipient + def recipient_paragraph bounding_box [margin_box.left, margin_box.top - 60], width: 200 do text order.name move_down 5 @@ -52,35 +67,47 @@ def body move_down 10 text "#{Delivery.human_attribute_name :date}:" move_down 10 - if order.supplier.try(:contact_person).present? - text "#{Supplier.human_attribute_name :contact_person}: #{order.supplier[:contact_person]}" - move_down 10 - end + return if order.supplier.try(:contact_person).blank? - # Articles + text "#{Supplier.human_attribute_name :contact_person}: #{order.supplier[:contact_person]}" + move_down 10 + end + + def articles_paragraph total = 0 - data = [I18n.t('documents.order_fax.rows')] + any_order_number_present = order_articles.where.not(article_version: { order_number: nil }).any? + data = [get_header_labels(!any_order_number_present)] each_order_article do |oa| - subtotal = oa.units_to_order * oa.price.unit_quantity * oa.price.price + price = oa.article_version.price + subtotal = oa.units_to_order * price total += subtotal - data << [oa.article.order_number, - oa.units_to_order, - oa.article.name, - oa.price.unit_quantity, - oa.article.unit, - number_to_currency(oa.price.price), - number_to_currency(subtotal)] + oa_data = [] + oa_data += [oa.article_version.order_number] if any_order_number_present + oa_data += [ + format_units_to_order(oa), + format_supplier_order_unit_with_ratios(oa.price), + oa.article_version.name, + number_to_currency(price), + number_to_currency(subtotal) + ] + data << oa_data end - data << [I18n.t('documents.order_fax.total'), nil, nil, nil, nil, nil, number_to_currency(total)] + + total_row_spacing_columns = [nil] * (any_order_number_present ? 4 : 3) + total_row = [I18n.t('documents.order_fax.total')] + total_row_spacing_columns + [number_to_currency(total)] + + data << total_row + table data, cell_style: { size: fontsize(8), overflow: :shrink_to_fit } do |table| table.header = true table.cells.border_width = 1 table.cells.border_color = '666666' table.row(0).border_bottom_width = 2 - table.columns(1).align = :right - table.columns(3..6).align = :right - table.row(data.length - 1).columns(0..5).borders = %i[top bottom] + table.columns(-5).align = :right + table.columns(-2..-1).align = :right + table.row(data.length - 1).columns(0).align = :left + table.row(data.length - 1).columns(0..-2).borders = %i[top bottom] table.row(data.length - 1).columns(0).borders = %i[top bottom left] table.row(data.length - 1).border_top_width = 2 end @@ -91,16 +118,20 @@ def body # align: {0 => :left} end - private - def order_articles order.order_articles.ordered - .joins(:article) - .order('articles.order_number').order('articles.name') - .preload(:article, :article_price) + .joins(:article_version) + .order('article_versions.order_number').order('article_versions.name') + .preload(article_version: :article) end def each_order_article(&block) order_articles.find_each_with_order(batch_size: BATCH_SIZE, &block) end + + def get_header_labels(exclude_order_number) + labels = I18n.t('documents.order_fax.rows').clone + labels.delete_at(0) if exclude_order_number + labels + end end diff --git a/app/documents/order_matrix.rb b/app/documents/order_matrix.rb index c45ca5fd5..9676b760a 100644 --- a/app/documents/order_matrix.rb +++ b/app/documents/order_matrix.rb @@ -15,17 +15,17 @@ def body order_articles_data = [[ OrderArticle.human_attribute_name(:article), Article.human_attribute_name(:supplier), - ArticlePrice.human_attribute_name(:unit_quantity), + ArticleVersion.human_attribute_name(:unit_quantity), OrderArticle.human_attribute_name(:units_received), Article.human_attribute_name(:fc_price_short) ]] - each_order_article do |a| - order_articles_data << [a.article.name, - a.article.supplier.name, - a.price.unit_quantity, - a.units, - order_article_price_per_unit(a)] + each_order_article do |oa| + order_articles_data << [oa.article_version.name, + oa.article_version.article.supplier.name, + oa.article_version.unit_quantity, + oa.units, + order_article_price_per_unit(oa)] end order_articles_data.each { |row| row.delete_at 1 } unless @options[:show_supplier] @@ -68,7 +68,7 @@ def body last_supplier_id = -1 each_order_article do |order_article| - supplier = order_article.article.supplier + supplier = order_article.article_version.article.supplier if @options[:show_supplier] && last_supplier_id != supplier.id row = [make_cell(supplier.name, colspan: 2, font_style: :bold)] batch_groups.each { row << nil } @@ -76,7 +76,7 @@ def body last_supplier_id = supplier.id end - row = [order_article.article.name, order_article_price_per_unit(order_article)] + row = [order_article.article_version.name, order_article_price_per_unit(order_article)] row += batch_results[order_article.id] if batch_results[order_article.id] rows << row end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4cd91e200..5efa4cdf9 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -267,4 +267,8 @@ def foodcoop_css_tag(_options = {}) stylesheet_link_tag foodcoop_css_path, media: 'all' end + + def format_number(value, max_precision = 2) + number_with_precision(value, precision: max_precision, strip_insignificant_zeros: true, separator: '.', delimiter: '') + end end diff --git a/app/helpers/articles_helper.rb b/app/helpers/articles_helper.rb index ebad29a4e..fe06921d3 100644 --- a/app/helpers/articles_helper.rb +++ b/app/helpers/articles_helper.rb @@ -1,9 +1,11 @@ module ArticlesHelper # useful for highlighting attributes, when synchronizing articles - def highlight_new(unequal_attributes, attribute) + def highlight_new(unequal_attributes, attributes) + attributes = [attributes] unless attributes.is_a?(Array) return unless unequal_attributes - unequal_attributes.has_key?(attribute) ? 'background-color: yellow' : '' + intersection = (unequal_attributes.keys & attributes) + intersection.empty? ? '' : 'background-color: yellow' end def row_classes(article) @@ -12,4 +14,126 @@ def row_classes(article) classes << 'just-updated' if article.recently_updated && article.availability classes.join(' ') end + + def format_supplier_order_unit(article) + format_unit(:supplier_order_unit, article) + end + + def format_group_order_unit(article) + format_unit(:group_order_unit, article) + end + + def format_billing_unit(article) + format_unit(:billing_unit, article) + end + + def format_price_unit(article) + format_unit(:price_unit, article) + end + + def format_supplier_order_unit_with_ratios(article) + format_unit_with_ratios(:supplier_order_unit, article) + end + + def format_group_order_unit_with_ratios(article) + format_unit_with_ratios(:group_order_unit, article) + end + + def format_billing_unit_with_ratios(article) + format_unit_with_ratios(:billing_unit, article) + end + + def field_with_preset_value_and_errors(options) + form, field, value, field_errors, input_html = options.values_at(:form, :field, :value, :errors, :input_html) + form.input field, label: false, wrapper_html: { class: field_errors.blank? ? '' : 'error' }, + input_html: input_html do + output = [form.input_field(field, { value: value }.merge(input_html))] + if field_errors.present? + errors = tag.span(class: 'help-inline') do + field_errors.join(', ') + end + output << errors + end + 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 diff --git a/app/helpers/deliveries_helper.rb b/app/helpers/deliveries_helper.rb index ac6e4b353..6d4aa0f14 100644 --- a/app/helpers/deliveries_helper.rb +++ b/app/helpers/deliveries_helper.rb @@ -10,7 +10,7 @@ def link_to_invoice(delivery) end def articles_for_select2(articles, except = [], &block) - articles = articles.reorder('articles.name ASC') + articles = articles.reorder('article_versions.name ASC') articles = articles.reject { |a| !except.index(a.id).nil? } if except block_given? or block = proc { |a| "#{a.name} (#{number_to_currency a.price}/#{a.unit})" } articles.map do |a| @@ -19,7 +19,7 @@ def articles_for_select2(articles, except = [], &block) end def articles_for_table(articles) - articles.undeleted.reorder('articles.name ASC') + articles.undeleted.reorder('article_versions.name ASC') end def stock_change_remove_link(stock_change_form) diff --git a/app/helpers/group_order_articles_helper.rb b/app/helpers/group_order_articles_helper.rb index 3a7efc33e..c970a0ccf 100644 --- a/app/helpers/group_order_articles_helper.rb +++ b/app/helpers/group_order_articles_helper.rb @@ -1,10 +1,25 @@ module GroupOrderArticlesHelper # return an edit field for a GroupOrderArticle result - def group_order_article_edit_result(goa) + def group_order_article_edit_result(goa, convert_to_billing_unit = true) result = number_with_precision goa.result, strip_insignificant_zeros: true if goa.group_order.order.finished? && current_user.role_finance? + order_article = goa.order_article + article_version = order_article.article_version simple_form_for goa, remote: true, html: { 'data-submit-onchange' => 'changed', class: 'delta-input' } do |f| - f.input_field :result, as: :delta, class: 'input-nano', data: { min: 0 }, id: "r_#{goa.id}", value: result + quantity_data = ratio_quantity_data(order_article, order_article.article_version.billing_unit) + converted_value = if convert_to_billing_unit + article_version.convert_quantity(goa.result, + article_version.group_order_unit, article_version.billing_unit) + else + result + end + input_data = { min: 0 }.merge(quantity_data) + if convert_to_billing_unit + input_data = input_data.merge('multiply-before-submit': article_version.convert_quantity(1, + article_version.billing_unit, article_version.group_order_unit)) + end + f.input_field(:result, as: :delta, class: 'input-nano', data: input_data, id: "r_#{goa.id}", + value: format_number(converted_value, 3)) end else result diff --git a/app/helpers/group_orders_helper.rb b/app/helpers/group_orders_helper.rb index a09a066c4..3406048b7 100644 --- a/app/helpers/group_orders_helper.rb +++ b/app/helpers/group_orders_helper.rb @@ -45,11 +45,11 @@ def get_order_results(order_article, group_order_id) { group_order_article: goa, quantity: quantity, tolerance: tolerance, result: result, sub_total: sub_total } end - def get_missing_units_css_class(quantity_missing) - if quantity_missing == 1 - 'missing-few' - elsif quantity_missing == 0 + def get_missing_units_css_class(quantity_missing, article_version) + if quantity_missing == 0 '' + elsif quantity_missing <= article_version.group_order_granularity + 'missing-few' else 'missing-many' end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb index d629ccb15..24c1d3c5f 100644 --- a/app/helpers/orders_helper.rb +++ b/app/helpers/orders_helper.rb @@ -23,24 +23,53 @@ def options_for_suppliers_to_select options_for_select(options) end + def format_units_to_order(order_article, strip_insignificant_zeros: false) + format_amount(order_article.units_to_order, order_article, strip_insignificant_zeros: strip_insignificant_zeros) + end + # "1×2 ordered, 2×2 billed, 2×2 received" def units_history_line(order_article, options = {}) if order_article.order.open? nil else units_info = [] + price = order_article.price %i[units_to_order units_billed units_received].map do |unit| next unless n = order_article.send(unit) - line = n.to_s + ' ' - line += pkg_helper(order_article.price, options) + ' ' unless n == 0 - line += OrderArticle.human_attribute_name("#{unit}_short", count: n) + converted_quantity = price.convert_quantity(n, price.supplier_order_unit, options[:unit].presence || price.supplier_order_unit) + line = converted_quantity.round(3).to_s + ' ' + line += pkg_helper(price, options) + ' ' unless n == 0 + line += OrderArticle.human_attribute_name("#{unit}_short", count: converted_quantity) units_info << line end units_info.join(', ').html_safe end end + def ordered_quantities_different_from_group_orders?(order_article, ordered_mark = '!', billed_mark = '?', + received_mark = '?') + price = order_article.price + group_orders_sum_quantity = order_article.group_orders_sum[:quantity] + if !order_article.units_received.nil? + if price.convert_quantity(order_article.units_received, price.supplier_order_unit, + price.group_order_unit).round(3) == group_orders_sum_quantity + false + else + received_mark + end + elsif !order_article.units_billed.nil? + order_article.units_billed == group_orders_sum_quantity ? false : billed_mark + elsif !order_article.units_to_order.nil? + if price.convert_quantity(order_article.units_to_order, price.supplier_order_unit, + price.group_order_unit).round(3) == group_orders_sum_quantity + false + else + ordered_mark + end + end + end + # @param article [Article] # @option options [String] :icon +false+ to hide the icon # @option options [String] :plain +true+ to not use HTML (implies +icon+=+false+) @@ -48,9 +77,16 @@ def units_history_line(order_article, options = {}) # Sensible in tables with multiple columns. # @return [String] Text showing unit and unit quantity when applicable. def pkg_helper(article, options = {}) - return '' if !article || article.unit_quantity == 1 + unit_code = options[:unit] || article.supplier_order_unit + if unit_code == article.supplier_order_unit + first_ratio = article&.article_unit_ratios&.first + return ArticleUnitsLib.human_readable_unit(unit_code) if first_ratio.nil? || first_ratio.quantity == 1 + + uq_text = "× #{number_with_precision(first_ratio.quantity, precision: 3, strip_insignificant_zeros: true)} #{ArticleUnitsLib.human_readable_unit(first_ratio.unit)}" + else + uq_text = ArticleUnitsLib.human_readable_unit(unit_code) + end - uq_text = "× #{article.unit_quantity}" uq_text = content_tag(:span, uq_text, class: 'hidden-phone') if options[:soft_uq] if options[:plain] uq_text @@ -73,36 +109,55 @@ def pkg_helper_icon(c = nil, options = {}) content_tag(options[:tag], c, class: "package #{options[:class]}").html_safe end - def article_price_change_hint(order_article, gross = false) - return nil if order_article.article.price == order_article.price.price + def article_version_change_hint(order_article, gross = false) + return nil if order_article.article_version.price == order_article.article_version.price - title = "#{t('helpers.orders.old_price')}: #{number_to_currency order_article.article.price}" - title += " / #{number_to_currency order_article.article.gross_price}" if gross + title = "#{t('helpers.orders.old_price')}: #{number_to_currency order_article.article_version.price}" + title += " / #{number_to_currency order_article.article_version.gross_price}" if gross content_tag(:i, nil, class: 'icon-asterisk', title: j(title)).html_safe end def receive_input_field(form) order_article = form.object - units_expected = (order_article.units_billed || order_article.units_to_order) * - 1.0 * order_article.article.unit_quantity / order_article.article_price.unit_quantity + price = order_article.article_version + quantity = order_article.units_billed || order_article.units_to_order + # units_expected = (order_article.units_billed || order_article.units_to_order) * + # 1.0 * order_article.article_version.unit_quantity / order_article.article_version.unit_quantity + units_expected = price.convert_quantity(quantity, price.supplier_order_unit, price.billing_unit) input_classes = 'input input-nano units_received' - input_classes += ' package' unless order_article.article_price.unit_quantity == 1 + input_classes += ' package' unless price.unit_quantity == 1 || price.supplier_order_unit != price.billing_unit + data = { units_expected: units_expected, billing_unit: price.billing_unit } + data.merge!(ratio_quantity_data(order_article, price.billing_unit)) input_html = form.text_field :units_received, class: input_classes, - data: { 'units-expected' => units_expected }, + data: data, disabled: order_article.result_manually_changed?, autocomplete: 'off' + span_html = if order_article.result_manually_changed? + content_tag(:span, class: 'input-prepend input-append intable', + title: t('orders.edit_amount.field_locked_title', default: '')) do + button_tag(nil, type: :button, class: 'btn unlocker') { + content_tag(:i, nil, class: 'icon icon-unlock') + } + input_html + end + else + content_tag(:span, class: 'input-append intable') { input_html } + end + + span_html.html_safe + end - if order_article.result_manually_changed? - input_html = content_tag(:span, class: 'input-prepend intable', - title: t('orders.edit_amount.field_locked_title', default: '')) do - button_tag(nil, type: :button, class: 'btn unlocker') { - content_tag(:i, nil, class: 'icon icon-unlock') - } + input_html - end + def ratio_quantity_data(order_article, default_unit = nil) + data = {} + data['supplier-order-unit'] = order_article.article_version.supplier_order_unit + data['default-unit'] = default_unit + data['custom-unit'] = order_article.article_version.unit + order_article.article_version.article_unit_ratios.all.each_with_index do |ratio, index| + data["ratio-quantity-#{index}"] = ratio.quantity + data["ratio-unit-#{index}"] = ratio.unit end - input_html.html_safe + data end # @param order [Order] @@ -155,4 +210,11 @@ def receive_button(order, options = {}) class: "btn#{' btn-success' unless order.received?} #{options[:class]}" end end + + private + + def format_amount(amount, order_article, strip_insignificant_zeros: false) + strip_insignificant_zeros = true unless order_article.article_version.supplier_order_unit_is_si_convertible + number_with_precision(amount, precision: 3, strip_insignificant_zeros: strip_insignificant_zeros) + end end diff --git a/app/helpers/suppliers_helper.rb b/app/helpers/suppliers_helper.rb index 507d20356..b2aff0f31 100644 --- a/app/helpers/suppliers_helper.rb +++ b/app/helpers/suppliers_helper.rb @@ -1,10 +1,8 @@ module SuppliersHelper - def associated_supplier_names(shared_supplier) - "(#{shared_supplier.suppliers.map(&:name).join(', ')})" - end - - def shared_sync_method_collection(shared_supplier) - shared_supplier.shared_sync_methods.map do |m| + def shared_sync_method_collection + # TODO: See if we really need the import limit `shared_supplier_article_sync_limit` + # also see https://github.com/foodcoops/foodsoft/pull/609/files and https://github.com/foodcoopsat/foodsoft_hackathon/issues/89 + Supplier.shared_sync_methods.keys.map do |m| [t("suppliers.shared_supplier_methods.#{m}"), m] end end diff --git a/app/inputs/delta_input.rb b/app/inputs/delta_input.rb index f4ce1a2b8..2a764b074 100644 --- a/app/inputs/delta_input.rb +++ b/app/inputs/delta_input.rb @@ -2,7 +2,8 @@ class DeltaInput < SimpleForm::Inputs::StringInput # for now, need to pass id or it won't work def input(wrapper_options) options = merge_wrapper_options(input_html_options, wrapper_options) - options[:type] = 'text' + options[:type] = 'number' + options[:step] = 'any' options[:data] ||= {} options[:data][:delta] ||= 1 options[:autocomplete] ||= 'off' @@ -10,8 +11,8 @@ def input(wrapper_options) template.content_tag :div, class: 'delta-input input-prepend input-append' do delta_button(content_tag(:i, nil, class: 'icon icon-minus'), -1, options) + - @builder.text_field(attribute_name, options) + - delta_button(content_tag(:i, nil, class: 'icon icon-plus'), 1, options) + delta_button(content_tag(:i, nil, class: 'icon icon-plus'), 1, options) + + @builder.text_field(attribute_name, options) end end # template.button_tag('−', type: :submit, data: {decrement: options[:id]}, tabindex: -1, class: 'btn') + @@ -21,6 +22,7 @@ def input(wrapper_options) def delta_button(title, direction, options) data = { (direction > 0 ? 'increment' : 'decrement') => options[:id] } delta = direction * options[:data][:delta] - template.button_tag(title, type: :button, name: 'delta', value: delta, data: data, tabindex: -1, class: 'btn') + template.button_tag(title, type: :button, name: 'delta', value: delta, data: data, tabindex: -1, + class: 'btn modify') end end diff --git a/app/lib/articles_csv.rb b/app/lib/articles_csv.rb index 61f5743fe..ac8350cd6 100644 --- a/app/lib/articles_csv.rb +++ b/app/lib/articles_csv.rb @@ -6,38 +6,59 @@ def header Article.human_attribute_name(:availability_short), Article.human_attribute_name(:order_number), Article.human_attribute_name(:name), - Article.human_attribute_name(:note), - Article.human_attribute_name(:manufacturer), - Article.human_attribute_name(:origin), - Article.human_attribute_name(:unit), + Article.human_attribute_name(:supplier_order_unit), + Article.human_attribute_name(:custom_unit), + Article.human_attribute_name(:ratios_to_supplier_order_unit), + Article.human_attribute_name(:minimum_order_quantity), + Article.human_attribute_name(:billing_unit), + Article.human_attribute_name(:group_order_granularity), + Article.human_attribute_name(:group_order_unit), Article.human_attribute_name(:price), + Article.human_attribute_name(:price_unit), Article.human_attribute_name(:tax), Article.human_attribute_name(:deposit), - Article.human_attribute_name(:unit_quantity), - '', - '', - Article.human_attribute_name(:article_category) + Article.human_attribute_name(:note), + Article.human_attribute_name(:article_category), + Article.human_attribute_name(:origin), + Article.human_attribute_name(:manufacturer) ] end def data - @object.each do |o| + @object.each do |article| yield [ - o.availability ? I18n.t('simple_form.yes') : I18n.t('simple_form.no'), - o.order_number, - o.name, - o.note, - o.manufacturer, - o.origin, - o.unit, - o.price, - o.tax, - o.deposit, - o.unit_quantity, - '', - '', - o.article_category.try(:name) + article.availability ? I18n.t('simple_form.yes') : I18n.t('simple_form.no'), + article.order_number, + article.name, + ArticleUnitsLib.get_translated_name_for_code(article.supplier_order_unit), + article.unit, + get_csv_ratios(article), + article.minimum_order_quantity, + ArticleUnitsLib.get_translated_name_for_code(article.billing_unit), + article.group_order_granularity, + ArticleUnitsLib.get_translated_name_for_code(article.group_order_unit), + article.price_unit_price, + ArticleUnitsLib.get_translated_name_for_code(article.price_unit), + article.tax, + article.deposit, + article.note, + article.article_category.try(:name), + article.origin, + article.manufacturer ] end end + + def get_csv_ratios(article) + previous_quantity = nil + article.article_unit_ratios.each_with_index.map do |ratio, _index| + quantity = previous_quantity.nil? ? ratio.quantity : ratio.quantity / previous_quantity + previous_quantity = ratio.quantity + "#{quantity} #{escape_csv_ratio(ArticleUnitsLib.get_translated_name_for_code(ratio.unit))}" + end.join(', ') + end + + def escape_csv_ratio(str) + str.gsub('\\', '\\\\').gsub(',', '\\,') + end end diff --git a/app/lib/foodsoft_file.rb b/app/lib/foodsoft_file.rb index 0a7128ed9..deca4d220 100644 --- a/app/lib/foodsoft_file.rb +++ b/app/lib/foodsoft_file.rb @@ -4,22 +4,50 @@ class FoodsoftFile # returns two arrays with articles and outlisted_articles # the parsed article is a simple hash def self.parse(file, options = {}) - SpreadsheetFile.parse file, options do |row, row_index| + articles = [] + SpreadsheetFile.parse file, options do |row| next if row[2].blank? - article = { order_number: row[1], + article = { availability: row[0]&.strip == I18n.t('simple_form.yes'), + order_number: row[1], name: row[2], - note: row[3], - manufacturer: row[4], - origin: row[5], - unit: row[6], - price: row[7], - tax: row[8], - deposit: (row[9].nil? ? '0' : row[9]), - unit_quantity: row[10], - article_category: row[13] } - status = row[0] && row[0].strip.downcase == 'x' ? :outlisted : nil - yield status, article, row_index + supplier_order_unit: ArticleUnitsLib.get_code_for_unit_name(row[3]), + unit: row[4], + article_unit_ratios: FoodsoftFile.parse_ratios_cell(row[5]), + minimum_order_quantity: row[6], + billing_unit: ArticleUnitsLib.get_code_for_unit_name(row[7]), + group_order_granularity: row[8], + group_order_unit: ArticleUnitsLib.get_code_for_unit_name(row[9]), + price: row[10], + price_unit: ArticleUnitsLib.get_code_for_unit_name(row[11]), + tax: row[12], + deposit: (row[13].nil? ? '0' : row[13]), + note: row[14], + article_category: row[15], + origin: row[16], + manufacturer: row[17] } + articles << article end + + articles + end + + def self.parse_ratios_cell(ratios_cell) + return [] if ratios_cell.blank? + + previous_quantity = nil + ratios = ratios_cell.split(/(?[+-]?(?:[0-9]*[.])?[0-9]+) (?.*)/) + quantity = md[:quantity].to_d + calculated_quantity = previous_quantity.nil? ? quantity : quantity * previous_quantity + previous_quantity = calculated_quantity + { + sort: index + 1, + quantity: calculated_quantity, + unit: ArticleUnitsLib.get_code_for_unit_name(md[:unit_name]) + } + end + + ratios.reject { |ratio| ratio[:unit].nil? } end end diff --git a/app/lib/order_csv.rb b/app/lib/order_csv.rb index e24495962..47a58b5fb 100644 --- a/app/lib/order_csv.rb +++ b/app/lib/order_csv.rb @@ -1,27 +1,29 @@ require 'csv' class OrderCsv < RenderCsv + include ApplicationHelper + include ArticlesHelper + include OrdersHelper + def header [ - OrderArticle.human_attribute_name(:units_to_order), Article.human_attribute_name(:order_number), - Article.human_attribute_name(:name), + OrderArticle.human_attribute_name(:units_to_order), Article.human_attribute_name(:unit), - Article.human_attribute_name(:unit_quantity_short), - ArticlePrice.human_attribute_name(:price), + Article.human_attribute_name(:name), + ArticleVersion.human_attribute_name(:price), OrderArticle.human_attribute_name(:total_price) ] end def data - @object.order_articles.ordered.includes(%i[article article_price]).all.map do |oa| + @object.order_articles.ordered.includes(:article_version).all.map do |oa| yield [ - oa.units_to_order, - oa.article.order_number, - oa.article.name, - oa.article.unit, - oa.price.unit_quantity > 1 ? oa.price.unit_quantity : nil, - number_to_currency(oa.price.price * oa.price.unit_quantity), + oa.article_version.order_number, + format_units_to_order(oa, strip_insignificant_zeros: true), + format_supplier_order_unit_with_ratios(oa.article_version), + oa.article_version.name, + number_to_currency(oa.article_version.price), number_to_currency(oa.total_price) ] end diff --git a/app/lib/order_pdf.rb b/app/lib/order_pdf.rb index 869cb0e83..3af817b7e 100644 --- a/app/lib/order_pdf.rb +++ b/app/lib/order_pdf.rb @@ -1,4 +1,5 @@ class OrderPdf < RenderPdf + include ArticlesHelper attr_reader :order def initialize(order, options = {}) @@ -47,21 +48,44 @@ def nice_table(name, data, dimrows = []) # @return [Number] Price to show # @see https://github.com/foodcoops/foodsoft/issues/445 def order_article_price(order_article) - order_article.price.fc_price + order_article.article_version.fc_group_order_price end def order_article_price_per_unit(order_article) - "#{number_to_currency(order_article_price(order_article))} / #{order_article.article.unit}" + "#{number_to_currency(order_article_price(order_article))} / #{format_group_order_unit_with_ratios(order_article.article_version)}" end - def group_order_article_quantity_with_tolerance(goa) - goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity.to_s + def price_per_billing_unit(goa) + article_version = goa.order_article.article_version + "#{number_to_currency(article_version.convert_quantity(article_version.fc_price, article_version.billing_unit, + article_version.supplier_order_unit))} / #{format_billing_unit_with_ratios(article_version)}" + end + + def billing_quantity_with_tolerance(goa) + article_version = goa.order_article.article_version + quantity = number_with_precision( + article_version.convert_quantity(goa.quantity, article_version.group_order_unit, + article_version.billing_unit), strip_insignificant_zeros: true, precision: 2 + ) + tolerance = number_with_precision( + article_version.convert_quantity(goa.tolerance, article_version.group_order_unit, + article_version.billing_unit), strip_insignificant_zeros: true, precision: 2 + ) + goa.tolerance > 0 ? "#{quantity} + #{tolerance}" : quantity end def group_order_article_result(goa) number_with_precision goa.result, strip_insignificant_zeros: true end + def billing_article_result(goa) + article_version = goa.order_article.article_version + number_with_precision( + article_version.convert_quantity(goa.result, article_version.group_order_unit, + article_version.billing_unit), precision: 2, strip_insignificant_zeros: true + ) + end + def group_order_articles(ordergroup) GroupOrderArticle .includes(:group_order) @@ -71,11 +95,11 @@ def group_order_articles(ordergroup) def order_articles OrderArticle .ordered - .includes(article: :supplier) + .includes(article_version: { article: :supplier }) .includes(group_order_articles: { group_order: :ordergroup }) .where(order: @orders) - .order('suppliers.name, articles.name, groups.name') - .preload(:article_price) + .order('suppliers.name, article_versions.name, groups.name') + .preload(:article_version) end def ordergroups(offset = nil, limit = nil) @@ -88,7 +112,7 @@ def ordergroups(offset = nil, limit = nil) .pluck('groups.name', 'SUM(group_orders.price)', 'ordergroup_id', 'SUM(group_orders.transport)') result.map do |item| - [item.first || stock_ordergroup_name] + item[1..] + [item.first || stock_ordergroup_name] + item[1..-1] end end @@ -103,7 +127,7 @@ def each_ordergroup(&block) def each_ordergroup_batch(batch_size) offset = 0 - loop do + while true go_records = ordergroups(offset, batch_size) break unless go_records.any? @@ -134,9 +158,9 @@ def each_group_order_article_for_order_article(order_article, &block) def each_group_order_article_for_ordergroup(ordergroup, &block) group_order_articles(ordergroup) - .includes(order_article: { article: [:supplier] }) - .order('suppliers.name, articles.name') - .preload(order_article: %i[article_price order]) + .includes(order_article: { article_version: { article: :supplier } }) + .order('suppliers.name, article_versions.name') + .preload(order_article: %i[article_version order]) .each(&block) end diff --git a/app/lib/order_txt.rb b/app/lib/order_txt.rb index 320e429f0..2ab22c654 100644 --- a/app/lib/order_txt.rb +++ b/app/lib/order_txt.rb @@ -1,4 +1,8 @@ class OrderTxt + include ActionView::Helpers::NumberHelper + include ArticlesHelper + include OrdersHelper + def initialize(order, _options = {}) @order = order end @@ -15,12 +19,61 @@ def to_txt text += '****** ' + I18n.t('orders.fax.to_address') + "\n\n" text += "#{FoodsoftConfig[:name]}\n#{contact[:street]}\n#{contact[:zip_code]} #{contact[:city]}\n\n" text += '****** ' + I18n.t('orders.fax.articles') + "\n\n" - text += format("%8s %8s %s\n", I18n.t('orders.fax.number'), I18n.t('orders.fax.amount'), - I18n.t('orders.fax.name')) - # now display all ordered articles - @order.order_articles.ordered.includes(%i[article article_price]).each do |oa| - text += format("%8s %8d %s\n", oa.article.order_number, oa.units_to_order.to_i, oa.article.name) + + # prepare order_articles data + order_articles = @order.order_articles.ordered.includes(:article_version).order('article_versions.order_number ASC, article_versions.name ASC') + any_number_present = order_articles.where.not(article_version: { order_number: nil }).any? + + order_headers = { + number: any_number_present ? { label: I18n.t('orders.fax.number') } : nil, + amount: { label: I18n.t('orders.fax.amount'), align: :right }, + unit: { label: I18n.t('orders.fax.unit') }, + name: { label: I18n.t('orders.fax.name') } + }.compact + + order_positions = order_articles.map do |oa| + number = oa.article_version.order_number || '' + amount = format_units_to_order(oa).to_s + unit = format_supplier_order_unit_with_ratios(oa.price) + { + number: number, + amount: amount, + unit: unit, + name: oa.article_version.name + } end + + text += text_table(order_headers, order_positions) text end + + private + + def text_table(headers, rows) + table_keys = headers.keys + columns = table_keys.each_with_index.map do |key, index| + header = headers[key] + label = header[:label] + { + key: key, + label: label, + align: header[:align], + characters: index + 1 < table_keys.length ? (rows.pluck(key) + [label]).map(&:length).max : nil + } + end + + header_txt = columns.map { |column| align_text_column(column[:label], column[:characters], column[:align]) }.join(' ') + + rows_texts = rows.map do |row| + columns.map { |column| align_text_column(row[column[:key]], column[:characters], column[:align]) }.join(' ') + end + + ([header_txt] + rows_texts).join("\n") + end + + def align_text_column(text, characters, align) + return text if characters.nil? + + align == :right ? text.rjust(characters) : text.ljust(characters) + end end diff --git a/app/models/article.rb b/app/models/article.rb index 289be1664..8f5356291 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -20,107 +20,113 @@ class Article < ApplicationRecord # @see http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements # @!attribute price # @return [Number] Net price - # @see ArticlePrice#price + # @see ArticleVersion#price # @!attribute tax # @return [Number] VAT percentage (10 is 10%). - # @see ArticlePrice#tax + # @see ArticleVersion#tax # @!attribute deposit # @return [Number] Deposit - # @see ArticlePrice#deposit + # @see ArticleVersion#deposit # @!attribute unit_quantity # @return [Number] Number of units in wholesale package (box). - # @see ArticlePrice#unit_quantity + # @see ArticleVersion#unit_quantity # @!attribute order_number # Order number, this can be used by the supplier to identify articles. # This is required when using the shared database functionality. # @return [String] Order number. # @!attribute article_category # @return [ArticleCategory] Category this article is in. - belongs_to :article_category # @!attribute supplier # @return [Supplier] Supplier this article belongs to. belongs_to :supplier - # @!attribute article_prices - # @return [Array] Price history (current price first). - has_many :article_prices, -> { order('created_at DESC') } - # @!attribute order_articles - # @return [Array] Order articles for this article. - has_many :order_articles + # @!attribute article_versions + # @return [Array] Price history (current price first). + has_many :article_versions, -> { order('created_at DESC') } + # @!attribute order # @return [Array] Orders this article appears in. has_many :orders, through: :order_articles - # Replace numeric seperator with database format - localize_input_of :price, :tax, :deposit - # Get rid of unwanted whitespace. {Unit#new} may even bork on whitespace. - normalize_attributes :name, :unit, :note, :manufacturer, :origin, :order_number + has_one :latest_article_version, lambda { + merge(ArticleVersion.latest) + }, foreign_key: :article_id, class_name: :ArticleVersion scope :undeleted, -> { where(deleted_at: nil) } - scope :available, -> { undeleted.where(availability: true) } + scope :available, -> { undeleted.with_latest_versions_and_categories.where(article_versions: { availability: true }) } scope :not_in_stock, -> { where(type: nil) } - # Validations - validates :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category, presence: true - validates :name, length: { in: 4..60 } - validates :unit, length: { in: 1..15 } - validates :note, length: { maximum: 255 } - validates :origin, length: { maximum: 255 } - validates :manufacturer, length: { maximum: 255 } - validates :order_number, length: { maximum: 255 } - validates :price, numericality: { greater_than_or_equal_to: 0 } - validates :unit_quantity, numericality: { greater_than: 0 } - validates :deposit, :tax, numericality: true - # validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type], if: Proc.new {|a| a.supplier.shared_sync_method.blank? or a.supplier.shared_sync_method == 'import' } - # validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type, :unit, :unit_quantity] - validate :uniqueness_of_name + scope :with_latest_versions_and_categories, lambda { + includes(:latest_article_version) + .joins(article_versions: [:article_category]) + .joins(ArticleVersion.latest_outer_join_sql("#{table_name}.#{primary_key}")) + .where(later_article_versions: { id: nil }) + } + + scope :with_latest_versions, lambda { + includes(:latest_article_version) + .joins(:article_versions) + .joins(ArticleVersion.latest_outer_join_sql("#{table_name}.#{primary_key}")) + .where(later_article_versions: { id: nil }) + } + + accepts_nested_attributes_for :latest_article_version + + # TODO: Remove these (see https://github.com/foodcoopsat/foodsoft_hackathon/issues/91): + begin + ArticleVersion.column_names.each do |column_name| + next if column_name == ArticleVersion.primary_key + next if column_name == 'article_id' + + delegate column_name, "#{column_name}=", to: :latest_article_version, allow_nil: true + end + rescue StandardError + # Ignore if these delegates cannot be created (can happen if table article_versions doesn't yet exist in migrations) + end + + delegate :article_category, to: :latest_article_version, allow_nil: true + delegate :article_unit_ratios, to: :latest_article_version, allow_nil: true # Callbacks - before_save :update_price_history + before_save :update_or_create_article_version before_destroy :check_article_in_use + after_save :reload_article_on_version_change def self.ransackable_attributes(_auth_object = nil) + # TODO: - see https://github.com/foodcoopsat/foodsoft_hackathon/issues/92 %w[id name supplier_id article_category_id unit note manufacturer origin unit_quantity order_number] end def self.ransackable_associations(_auth_object = nil) + # TODO: - see https://github.com/foodcoopsat/foodsoft_hackathon/issues/92 %w[article_category supplier order_articles orders] end # Returns true if article has been updated at least 2 days ago def recently_updated - updated_at > 2.days.ago + latest_article_version.updated_at > 2.days.ago end # If the article is used in an open Order, the Order will be returned. def in_open_order @in_open_order ||= begin order_articles = OrderArticle.where(order_id: Order.open.collect(&:id)) - order_article = order_articles.detect { |oa| oa.article_id == id } - order_article&.order + order_article = order_articles.detect { |oa| oa.article_version.article_id == id } + order_article ? order_article.order : nil end end # Returns true if the article has been ordered in the given order at least once def ordered_in_order?(order) - order.order_articles.where(article_id: id).where('quantity > 0').one? + order.order_articles.includes(:article_version).where(article_version: { article_id: id }).where('quantity > 0').one? end - # this method checks, if the shared_article has been changed - # unequal attributes will returned in array - # if only the timestamps differ and the attributes are equal, - # false will returned and self.shared_updated_on will be updated - def shared_article_changed?(supplier = self.supplier) - # skip early if the timestamp hasn't changed - shared_article = self.shared_article(supplier) - return if shared_article.nil? || shared_updated_on == shared_article.updated_on - - attrs = unequal_attributes(shared_article) - if attrs.empty? - # when attributes not changed, update timestamp of article - update_attribute(:shared_updated_on, shared_article.updated_on) - false - else - attrs + # to get the correspondent shared article + def shared_article(supplier = self.supplier) + order_number.blank? and return nil + @shared_article ||= begin + supplier.shared_supplier.find_article_by_number(order_number) + rescue StandardError + nil end end @@ -144,51 +150,52 @@ def unequal_attributes(new_article, options = {}) new_unit = new_article.unit end - Article.compare_attributes( + ret = ArticleVersion.compare_attributes( { - name: [name, new_article.name], - manufacturer: [manufacturer, new_article.manufacturer.to_s], - origin: [origin, new_article.origin], - unit: [unit, new_unit], - price: [price.to_f.round(2), new_price.to_f.round(2)], - tax: [tax, new_article.tax], - deposit: [deposit.to_f.round(2), new_article.deposit.to_f.round(2)], - # take care of different num-objects. - unit_quantity: [unit_quantity.to_s.to_f, new_unit_quantity.to_s.to_f], - note: [note.to_s, new_article.note.to_s] + name: [latest_article_version.name, new_article.name], + manufacturer: [latest_article_version.manufacturer, new_article.manufacturer.to_s], + origin: [latest_article_version.origin, new_article.origin], + unit: [latest_article_version.unit, new_unit], + supplier_order_unit: [latest_article_version.supplier_order_unit, new_article.supplier_order_unit], + minimum_order_quantity: [latest_article_version.minimum_order_quantity, new_article.minimum_order_quantity], + billing_unit: [latest_article_version.billing_unit || latest_article_version.supplier_order_unit, + new_article.billing_unit || new_article.supplier_order_unit], + group_order_granularity: [latest_article_version.group_order_granularity, new_article.group_order_granularity], + group_order_unit: [latest_article_version.group_order_unit, new_article.group_order_unit], + price: [latest_article_version.price.to_f.round(2), new_price.to_f.round(2)], + tax: [latest_article_version.tax, new_article.tax], + deposit: [latest_article_version.deposit.to_f.round(2), new_article.deposit.to_f.round(2)], + note: [latest_article_version.note.to_s, new_article.note.to_s] } ) - end - # Compare attributes from two different articles. - # - # This is used for auto-synchronization - # @param attributes [Hash] Attributes with old and new values - # @return [Hash] Changed attributes with new values - def self.compare_attributes(attributes) - unequal_attributes = attributes.select do |_name, values| - values[0] != values[1] && !(values[0].blank? && values[1].blank?) + ratios_differ = latest_article_version.article_unit_ratios.length != new_article.article_unit_ratios.length || + latest_article_version.article_unit_ratios.each_with_index.any? do |article_unit_ratio, index| + new_article.article_unit_ratios[index].unit != article_unit_ratio.unit || + new_article.article_unit_ratios[index].quantity != article_unit_ratio.quantity + end + + if ratios_differ + ratio_attribs = new_article.article_unit_ratios.map(&:attributes) + ret[:article_unit_ratios_attributes] = ratio_attribs end - unequal_attributes.to_a.map { |a| [a[0], a[1].last] }.to_h - end - # to get the correspondent shared article - def shared_article(supplier = self.supplier) - order_number.blank? and return nil - @shared_article ||= begin - supplier.shared_supplier.find_article_by_number(order_number) - rescue StandardError - nil + if options[:convert_units] && latest_article_version.article_unit_ratios.length < 2 && new_article.article_unit_ratios.length < 2 && !new_unit_quantity.nil? + ret[:article_unit_ratios_attributes] = [new_article.article_unit_ratios.build(unit: 'XPP', quantity: new_unit_quantity, sort: 1).attributes] + # TODO: Either remove this aspect of the :convert_units feature or extend it to also work for the new units system (see https://github.com/foodcoopsat/foodsoft_hackathon/issues/90) end + + ret end # convert units in foodcoop-size # uses unit factors in app_config.yml to calc the price/unit_quantity - # returns new price and unit_quantity in array, when calc is possible => [price, unit_quanity] + # returns new price and unit_quantity in array, when calc is possible => [price, unit_quantity] # returns false if units aren't foodsoft-compatible # returns nil if units are eqal def convert_units(new_article = shared_article) return unless unit != new_article.unit + return false if new_article.unit.include?(',') # legacy, used by foodcoops in Germany @@ -232,6 +239,19 @@ def mark_as_deleted update_column :deleted_at, Time.now end + def current_article_units + [supplier_order_unit, group_order_unit, billing_unit, price_unit, article_unit_ratios.map(&:unit)] + .flatten + .uniq + .compact + end + + def duplicate_including_latest_version_and_ratios + article = dup + article.latest_article_version = latest_article_version.duplicate_including_article_unit_ratios + article + end + protected # Checks if the article is in use before it will deleted @@ -239,33 +259,35 @@ def check_article_in_use raise I18n.t('articles.model.error_in_use', article: name.to_s) if in_open_order end - # Create an ArticlePrice, when the price-attr are changed. - def update_price_history - return unless price_changed? + # Create an ArticleVersion, when the price-attr are changed. + def update_or_create_article_version + @version_changed_before_save = false + return unless version_dup_required? - article_prices.build( - price: price, - tax: tax, - deposit: deposit, - unit_quantity: unit_quantity - ) + old_version = latest_article_version + new_version = old_version.duplicate_including_article_unit_ratios + article_versions << new_version + + OrderArticle.belonging_to_open_order + .joins(:article_version) + .where(article_versions: { article_id: id }) + .update_all(article_version_id: new_version.id) + + # reload old version to avoid updating it too (would automatically happen after before_save): + old_version.reload + + @version_changed_before_save = true end - def price_changed? - changed.detect { |attr| attr == 'price' || 'tax' || 'deposit' || 'unit_quantity' } ? true : false + def reload_article_on_version_change + reload if @version_changed_before_save + @version_changed_before_save = false end - # We used have the name unique per supplier+deleted_at+type. With the addition of shared_sync_method all, - # this came in the way, and we now allow duplicate names for the 'all' methods - expecting foodcoops to - # make their own choice among products with different units by making articles available/unavailable. - def uniqueness_of_name - matches = Article.where(name: name, supplier_id: supplier_id, deleted_at: deleted_at, type: type) - matches = matches.where.not(id: id) unless new_record? - # supplier should always be there - except, perhaps, on initialization (on seeding) - if supplier && (supplier.shared_sync_method.blank? || supplier.shared_sync_method == 'import') - errors.add :name, :taken if matches.any? - elsif matches.where(unit: unit, unit_quantity: unit_quantity).any? - errors.add :name, :taken_with_unit - end + def version_dup_required? + return false if latest_article_version.nil? + return false unless latest_article_version.self_or_ratios_changed? + + OrderArticle.belonging_to_finished_order.exists?(article_version_id: latest_article_version.id) end end diff --git a/app/models/article_price.rb b/app/models/article_price.rb deleted file mode 100644 index ac3b2b4ca..000000000 --- a/app/models/article_price.rb +++ /dev/null @@ -1,31 +0,0 @@ -class ArticlePrice < ApplicationRecord - include LocalizeInput - include PriceCalculation - - # @!attribute price - # @return [Number] Net price - # @see Article#price - # @!attribute tax - # @return [Number] VAT percentage - # @see Article#tax - # @!attribute deposit - # @return [Number] Deposit - # @see Article#deposit - # @!attribute unit_quantity - # @return [Number] Number of units in wholesale package (box). - # @see Article#unit - # @see Article#unit_quantity - # @!attribute article - # @return [Article] Article this price is about. - belongs_to :article - # @!attribute order_articles - # @return [Array] Order articles this price is associated with. - has_many :order_articles - - localize_input_of :price, :tax, :deposit - - validates :price, :tax, :deposit, :unit_quantity, presence: true - validates :price, numericality: { greater_than_or_equal_to: 0 } - validates :unit_quantity, numericality: { greater_than: 0 } - validates :deposit, :tax, numericality: true -end diff --git a/app/models/article_unit.rb b/app/models/article_unit.rb new file mode 100644 index 000000000..296fce544 --- /dev/null +++ b/app/models/article_unit.rb @@ -0,0 +1,43 @@ +class ArticleUnit < ApplicationRecord + self.primary_key = :unit + + before_save { ArticleUnit.clear_cache } + before_destroy { ArticleUnit.clear_cache } + + def self.all_cached + @all_cached = {} if @all_cached.nil? + cached_units_in_locale = @all_cached[I18n.locale] + return cached_units_in_locale unless cached_units_in_locale.nil? + + @all_cached[I18n.locale] = all.load + end + + def self.clear_cache + @all_cached = {} + end + + def self.as_hash(config = nil) + additional_units = config&.dig(:additional_units) || [] + available_units = all_cached.map(&:unit) + ArticleUnitsLib.units.to_h do |code, unit| + [code, unit.merge({ visible: available_units.include?(code) || additional_units.include?(code) })] + end + end + + def self.as_options(config = nil) + additional_units = config&.dig(:additional_units) || [] + options = {} + + available_units = all_cached.map(&:unit) + ArticleUnitsLib.units.each do |code, unit| + next unless available_units.include?(code) || additional_units.include?(code) + + label = unit[:name] + label += " (#{unit[:symbol]})" if unit[:symbol].present? + + options[label] = code + end + + options + end +end diff --git a/app/models/article_unit_ratio.rb b/app/models/article_unit_ratio.rb new file mode 100644 index 000000000..69381b20c --- /dev/null +++ b/app/models/article_unit_ratio.rb @@ -0,0 +1,6 @@ +class ArticleUnitRatio < ApplicationRecord + belongs_to :article_version + + validates :quantity, :sort, :unit, presence: true + validates :quantity, numericality: { greater_than: 0, less_than: 10**35 } +end diff --git a/app/models/article_version.rb b/app/models/article_version.rb new file mode 100644 index 000000000..9bed9aa3e --- /dev/null +++ b/app/models/article_version.rb @@ -0,0 +1,206 @@ +class ArticleVersion < ApplicationRecord + include LocalizeInput + include PriceCalculation + + # @!attribute price + # @return [Number] Net price + # @see Article#price + # @!attribute tax + # @return [Number] VAT percentage + # @see Article#tax + # @!attribute deposit + # @return [Number] Deposit + # @see Article#deposit + # @!attribute unit_quantity + # @return [Number] Number of units in wholesale package (box). + # @see Article#unit + # @see Article#unit_quantity + # @!attribute article + # @return [Article] Article this price is about. + belongs_to :article + belongs_to :article_category + # @!attribute order_articles + # @return [Array] Order articles this price is associated with. + has_many :order_articles + + has_many :article_unit_ratios, after_add: :on_article_unit_ratios_change, + after_remove: :on_article_unit_ratios_change, dependent: :destroy + + localize_input_of :price, :tax, :deposit + + # Validations + validates :name, :price, :tax, :deposit, :article_category, presence: true + validates :name, length: { in: 4..60 } + validates :unit, length: { in: 1..15, unless: :supplier_order_unit } + validates :supplier_order_unit, presence: { unless: :unit } + validates :note, length: { maximum: 255 } + validates :origin, length: { maximum: 255 } + validates :manufacturer, length: { maximum: 255 } + validates :order_number, length: { maximum: 255 } + validates :price, numericality: { greater_than_or_equal_to: 0 } + validates :group_order_granularity, numericality: { greater_than_or_equal_to: 0 } + validates :deposit, :tax, numericality: true + validates :minimum_order_quantity, numericality: { allow_nil: true } + + # validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type], if: Proc.new {|a| a.supplier.shared_sync_method.blank? or a.supplier.shared_sync_method == 'import' } + # validates_uniqueness_of :name, :scope => [:supplier_id, :deleted_at, :type, :unit, :unit_quantity] + validate :uniqueness_of_name + validate :only_one_unit_type + validate :minimum_order_quantity_as_integer, unless: :supplier_order_unit_is_si_convertible + + # Replace numeric seperator with database format + localize_input_of :price, :tax, :deposit + # Get rid of unwanted whitespace. {Unit#new} may even bork on whitespace. + normalize_attributes :name, :unit, :note, :manufacturer, :origin, :order_number + + accepts_nested_attributes_for :article_unit_ratios, allow_destroy: true + + scope :latest, lambda { + joins(latest_outer_join_sql("#{table_name}.article_id")).where(later_article_versions: { id: nil }) + } + + def self.latest_outer_join_sql(article_field_name) + %( + LEFT OUTER JOIN #{table_name} later_article_versions + ON later_article_versions.article_id = #{article_field_name} + AND later_article_versions.created_at > #{table_name}.created_at + ) + end + + def supplier_order_unit_is_si_convertible + ArticleUnitsLib.unit_is_si_convertible(supplier_order_unit) + end + + # TODO: Maybe use the `nilify_blanks` gem instead of the following six methods? (see https://github.com/foodcoopsat/foodsoft_hackathon/issues/93): + def unit=(value) + if value.blank? + self[:unit] = nil + else + super + end + end + + def supplier_order_unit=(value) + if value.blank? + self[:supplier_order_unit] = nil + else + super + end + end + + def group_order_unit=(value) + if value.blank? + self[:group_order_unit] = nil + else + super + end + end + + def price_unit=(value) + if value.blank? + self[:price_unit] = nil + else + super + end + end + + def billing_unit=(value) + if value.blank? + self[:billing_unit] = nil + else + super + end + end + + def minimum_order_quantity=(value) + if value.blank? + self[:minimum_order_quantity] = nil + else + super + end + end + + def self_or_ratios_changed? + changed? || @article_unit_ratios_changed || article_unit_ratios.any?(&:changed?) + end + + def duplicate_including_article_unit_ratios + new_version = dup + article_unit_ratios.each do |ratio| + ratio = ratio.dup + ratio.article_version_id = nil + new_version.article_unit_ratios << ratio + end + + new_version + end + + # Compare attributes from two different articles. + # + # This is used for auto-synchronization + # @param attributes [Hash] Attributes with old and new values + # @return [Hash] Changed attributes with new values + def self.compare_attributes(attributes) + unequal_attributes = attributes.select do |_name, values| + values[0] != values[1] && !(values[0].blank? && values[1].blank?) + end + unequal_attributes.to_a.map { |a| [a[0], a[1].last] }.to_h + end + + def uses_tolerance? + ( + !supplier_order_unit_is_si_convertible && + convert_quantity(1, supplier_order_unit, group_order_unit) != group_order_granularity + ) || (minimum_order_quantity.presence || 0) > group_order_granularity + end + + protected + + # We used have the name unique per supplier+deleted_at+type. With the addition of shared_sync_method all, + # this came in the way, and we now allow duplicate names for the 'all' methods - expecting foodcoops to + # make their own choice among products with different units by making articles available/unavailable. + def uniqueness_of_name + matches = Article.with_latest_versions.where(article_versions: { name: name }, + supplier_id: article.supplier_id, + deleted_at: article.deleted_at, + type: article.type) + matches = matches.where.not(id: article.id) unless article.new_record? + # supplier should always be there - except, perhaps, on initialization (on seeding) + if article.supplier && (article.supplier.shared_sync_method.blank? || article.supplier.shared_sync_method == 'import') + errors.add :name, :taken if matches.any? + else + article_unit_ratios.each_with_index do |article_unit_ratio, index| + matches = matches.joins(%( + INNER JOIN #{ArticleUnitRatio.table_name} #{ArticleUnitRatio.table_name}_#{index} + ON #{ArticleUnitRatio.table_name}_#{index}.article_version_id = #{ArticleVersion.table_name}.id + AND #{ArticleUnitRatio.table_name}_#{index}.sort = #{ArticleUnitRatio.connection.quote(article_unit_ratio.sort)} + AND #{ArticleUnitRatio.table_name}_#{index}.unit = #{ArticleUnitRatio.connection.quote(article_unit_ratio.unit)} + AND #{ArticleUnitRatio.table_name}_#{index}.quantity = #{ArticleUnitRatio.connection.quote(article_unit_ratio.quantity)} + )) + end + + errors.add :name, :taken_with_unit if matches.where(article_versions: { supplier_order_unit: supplier_order_unit, unit: unit }).any? + end + end + + def minimum_order_quantity_as_integer + begin + return if Float(minimum_order_quantity) % 1 == 0 + rescue ArgumentError, TypeError + # not any number -> let numericality validation handle this + return + end + + errors.add(:minimum_order_quantity, :only_integer) + end + + def only_one_unit_type + return if unit.blank? || supplier_order_unit.blank? + + errors.add :unit # not specifying a specific error message as this should be prevented by js + end + + def on_article_unit_ratios_change(_some_change) + @article_unit_ratios_changed = true + end +end diff --git a/app/models/concerns/price_calculation.rb b/app/models/concerns/price_calculation.rb index 8d56d6715..1a0c2c7c2 100644 --- a/app/models/concerns/price_calculation.rb +++ b/app/models/concerns/price_calculation.rb @@ -1,6 +1,21 @@ module PriceCalculation extend ActiveSupport::Concern + class UnsupportedUnitConversionError < StandardError + def initialize(msg = 'Unit not supported') + super + end + end + + def unit_quantity + first_ratio = article_unit_ratios.first + if first_ratio.nil? + 1 + else + first_ratio.quantity + end + end + # Gross price = net price + deposit + tax. # @return [Number] Gross price. def gross_price @@ -12,6 +27,51 @@ def fc_price add_percent(gross_price, FoodsoftConfig[:price_markup].to_i) end + # get the unit ratio quantity in reference to the supplier_order_unit + def get_unit_ratio_quantity(unit) + return 1 if unit == supplier_order_unit + + ratio = new_record? ? article_unit_ratios.detect { |ratio| ratio[:unit] == unit } : article_unit_ratios.find_by_unit(unit) + return ratio.quantity unless ratio.nil? + + unit_hash = ArticleUnit.as_hash[unit] + raise UnsupportedUnitConversionError, "unit '#{unit}' is unknown" if unit_hash.nil? + + related_ratio = article_unit_ratios.detect do |current_ratio| + ArticleUnit.as_hash[current_ratio.unit][:baseUnit] == unit_hash[:baseUnit] + end + return related_ratio.quantity / unit_hash[:conversionFactor] * ArticleUnit.as_hash[related_ratio.unit][:conversionFactor] unless related_ratio.nil? + + supplier_order_unit_conversion_factor = ArticleUnit.as_hash[supplier_order_unit]&.dig(:conversionFactor) + raise UnsupportedUnitConversionError, "supplier_order_unit '#{supplier_order_unit}' is unknown or has no conversionFactor" if supplier_order_unit_conversion_factor.nil? + + supplier_order_unit_conversion_factor / unit_hash[:conversionFactor] + end + + def convert_quantity(quantity, input_unit, output_unit) + quantity / get_unit_ratio_quantity(input_unit) * get_unit_ratio_quantity(output_unit) + end + + def group_order_price(value = nil) + value ||= price + # price is always stored in supplier_order_unit: + value / convert_quantity(1, supplier_order_unit, group_order_unit) + end + + def price_unit_price(value = nil) + value ||= price + # price is always stored in supplier_order_unit: + value / convert_quantity(1, supplier_order_unit, price_unit) + end + + def gross_group_order_price + group_order_price(gross_price) + end + + def fc_group_order_price + group_order_price(fc_price) + end + private def add_percent(value, percent) diff --git a/app/models/group_order.rb b/app/models/group_order.rb index 183b663ae..b48c9f71f 100644 --- a/app/models/group_order.rb +++ b/app/models/group_order.rb @@ -44,8 +44,8 @@ def load_data # Build hash with relevant data data[:order_articles][order_article.id] = { - price: order_article.article.fc_price, - unit: order_article.article.unit_quantity, + price: order_article.article_version.fc_group_order_price, + unit: order_article.article_version.unit_quantity, quantity: (goa ? goa.quantity : 0), others_quantity: order_article.quantity - (goa ? goa.quantity : 0), used_quantity: (goa ? goa.result(:quantity) : 0), @@ -54,7 +54,14 @@ def load_data used_tolerance: (goa ? goa.result(:tolerance) : 0), total_price: (goa ? goa.total_price : 0), missing_units: order_article.missing_units, - quantity_available: (order.stockit? ? order_article.article.quantity_available : 0) + ratio_group_order_unit_supplier_unit: order_article.article_version.convert_quantity(1, + order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit), + quantity_available: (order.stockit? ? order_article.article_version.article.quantity_available : 0), + minimum_order_quantity: if order_article.article_version.minimum_order_quantity + order_article.article_version.convert_quantity( + order_article.article_version.minimum_order_quantity, order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit + ) + end } end end @@ -70,7 +77,7 @@ def save_group_order_articles # Get ordered quantities and update group_order_articles/_quantities... if group_order_articles_attributes quantities = group_order_articles_attributes.fetch(order_article.id.to_s, { quantity: 0, tolerance: 0 }) - group_order_article.update_quantities(quantities[:quantity].to_i, quantities[:tolerance].to_i) + group_order_article.update_quantities(quantities[:quantity].to_f, quantities[:tolerance].to_f) end # Also update results for the order_article @@ -83,7 +90,7 @@ def save_group_order_articles # Updates the "price" attribute. def update_price! - total = group_order_articles.includes(order_article: %i[article article_price]).to_a.sum(&:total_price) + total = group_order_articles.includes(order_article: :article_version).to_a.sum(&:total_price) update_attribute(:price, total) end @@ -97,12 +104,7 @@ def save_ordering! end def ordergroup_name - if ordergroup - ordergroup.name - else - I18n.t('model.group_order.stock_ordergroup_name', - user: updated_by.try(:name) || '?') - end + ordergroup ? ordergroup.name : I18n.t('model.group_order.stock_ordergroup_name', user: updated_by.try(:name) || '?') end def total diff --git a/app/models/group_order_article.rb b/app/models/group_order_article.rb index 7b95d462d..50cb37963 100644 --- a/app/models/group_order_article.rb +++ b/app/models/group_order_article.rb @@ -3,7 +3,6 @@ # class GroupOrderArticle < ApplicationRecord include LocalizeInput - belongs_to :group_order belongs_to :order_article has_many :group_order_article_quantities, dependent: :destroy @@ -11,7 +10,7 @@ class GroupOrderArticle < ApplicationRecord validates :group_order, :order_article, presence: true validates :order_article_id, uniqueness: { scope: :group_order_id } # just once an article per group order validate :check_order_not_closed # don't allow changes to closed (aka settled) orders - validates :quantity, :tolerance, numericality: { only_integer: true, greater_than_or_equal_to: 0 } + validates :quantity, :tolerance, numericality: { greater_than_or_equal_to: 0 } scope :ordered, -> { includes(group_order: :ordergroup).order('groups.name') } @@ -68,14 +67,14 @@ def update_quantities(quantity, tolerance) logger.debug("Need to decrease quantities for GroupOrderArticleQuantity[#{quantities[i].id}]") if quantity < self.quantity && quantities[i].quantity > 0 delta = self.quantity - quantity - delta = [delta, quantities[i].quantity].min + delta = (delta > quantities[i].quantity ? quantities[i].quantity : delta) logger.debug("Decreasing quantity by #{delta}") quantities[i].quantity -= delta self.quantity -= delta end if tolerance < self.tolerance && quantities[i].tolerance > 0 delta = self.tolerance - tolerance - delta = [delta, quantities[i].tolerance].min + delta = (delta > quantities[i].tolerance ? quantities[i].tolerance : delta) logger.debug("Decreasing tolerance by #{delta}") quantities[i].tolerance -= delta self.tolerance -= delta @@ -125,13 +124,14 @@ def calculate_result(total = nil) # Get total if !total.nil? - logger.debug "<#{order_article.article.name}> => #{total} (given)" - elsif order_article.article.is_a?(StockArticle) - total = order_article.article.quantity - logger.debug "<#{order_article.article.name}> (stock) => #{total}" + logger.debug "<#{order_article.article_version.name}> => #{total} (given)" + elsif order_article.article_version.is_a?(StockArticle) + total = order_article.article_version.quantity + logger.debug "<#{order_article.article_version.name}> (stock) => #{total}" else - total = order_article.units_to_order * order_article.price.unit_quantity - logger.debug "<#{order_article.article.name}> units_to_order #{order_article.units_to_order} => #{total}" + total = order_article.article_version.convert_quantity(order_article.units_to_order, + order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit) + logger.debug "<#{order_article.article_version.name}> units_to_order #{order_article.units_to_order} => #{total}" end if total > 0 @@ -197,14 +197,15 @@ def save_results!(article_total = nil) # the minimum price depending on configuration. When the order is finished it # will be the value depending of the article results. def total_price(order_article = self.order_article) + group_order_price = order_article.article_version.fc_group_order_price if order_article.order.open? if FoodsoftConfig[:tolerance_is_costly] - order_article.article.fc_price * (quantity + tolerance) + group_order_price * (quantity + tolerance) else - order_article.article.fc_price * quantity + group_order_price * quantity end else - order_article.price.fc_price * result + group_order_price * result end end diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 781b1f1f4..616a03232 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -21,6 +21,7 @@ class Invoice < ApplicationRecord # Replace numeric seperator with database format localize_input_of :amount, :deposit, :deposit_credit + def user_can_edit?(user) user.role_finance? || (user.role_invoices? && !paid_on && created_by.try(:id) == user.id) end @@ -32,10 +33,9 @@ def net_amount def orders_sum orders - .joins(order_articles: [:article_price]) + .joins(order_articles: [:article_version]) .sum('COALESCE(order_articles.units_received, order_articles.units_billed, order_articles.units_to_order)' \ - + '* article_prices.unit_quantity' \ - + '* ROUND((article_prices.price + article_prices.deposit) * (100 + article_prices.tax) / 100, 2)') + + '* ROUND((article_versions.price + article_versions.deposit) * (100 + article_versions.tax) / 100, 2)') end def orders_transport_sum diff --git a/app/models/order.rb b/app/models/order.rb index 23c19baab..7eb797399 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -3,7 +3,8 @@ class Order < ApplicationRecord # Associations has_many :order_articles, dependent: :destroy - has_many :articles, through: :order_articles + has_many :article_versions, through: :order_articles + has_many :articles, through: :article_versions has_many :group_orders, dependent: :destroy has_many :ordergroups, through: :group_orders has_many :users_ordered, through: :ordergroups, source: :users @@ -69,8 +70,8 @@ def articles_for_ordering if stockit? # make sure to include those articles which are no longer available # but which have already been ordered in this stock order - StockArticle.available.includes(:article_category) - .order('article_categories.name', 'articles.name').reject do |a| + StockArticle.available.includes(latest_article_version: :article_category) + .order('article_categories.name', 'article_versions.name').reject do |a| a.quantity_available <= 0 && !a.ordered_in_order?(self) end.group_by { |a| a.article_category.name } else @@ -80,9 +81,9 @@ def articles_for_ordering def supplier_articles if stockit? - StockArticle.undeleted.reorder('articles.name') + StockArticle.undeleted.with_latest_versions_and_categories.reorder('article_versions.name') else - supplier.articles.undeleted.reorder('articles.name') + supplier.articles.undeleted.with_latest_versions_and_categories.reorder('article_versions.name') end end @@ -90,7 +91,7 @@ def supplier_articles attr_writer :article_ids def article_ids - @article_ids ||= order_articles.map { |a| a.article_id.to_s } + @article_ids ||= order_articles.map { |oa| oa.article_version.article_id.to_s } end # Returns an array of article ids that lead to a validation error. @@ -177,9 +178,10 @@ def stock_group_order # e.g: [["drugs",[teethpaste, toiletpaper]], ["fruits" => [apple, banana, lemon]]] def articles_grouped_by_category @articles_grouped_by_category ||= order_articles - .includes([:article_price, :group_order_articles, { article: :article_category }]) - .order('articles.name') - .group_by { |a| a.article.article_category.name } + .includes([:article_version, :group_order_articles, + { article_version: :article_category }]) + .order('article_versions.name') + .group_by { |oa| oa.article_version.article_category.name } .sort { |a, b| a[0] <=> b[0] } end @@ -208,25 +210,26 @@ def profit(options = {}) def sum(type = :gross) total = 0 if %i[net gross fc].include?(type) - for oa in order_articles.ordered.includes(:article, :article_price) - quantity = oa.units * oa.price.unit_quantity + for oa in order_articles.ordered.includes(:article_version) + quantity = oa.units * oa.article_version.convert_quantity(1, oa.article_version.supplier_order_unit, + oa.article_version.group_order_unit) case type when :net - total += quantity * oa.price.price + total += quantity * oa.article_version.group_order_price when :gross - total += quantity * oa.price.gross_price + total += quantity * oa.article_version.gross_group_order_price when :fc - total += quantity * oa.price.fc_price + total += quantity * oa.article_version.fc_group_order_price end end elsif %i[groups groups_without_markup].include?(type) - for go in group_orders.includes(group_order_articles: { order_article: %i[article article_price] }) + for go in group_orders.includes(group_order_articles: { order_article: :article_version }) for goa in go.group_order_articles case type when :groups - total += goa.result * goa.order_article.price.fc_price + total += goa.result * goa.order_article.article_version.fc_group_order_price when :groups_without_markup - total += goa.result * goa.order_article.price.gross_price + total += goa.result * goa.order_article.article_version.gross_group_order_price end end end @@ -243,19 +246,12 @@ def finish!(user) # set new order state (needed by notify_order_finished) update!(state: 'finished', ends: Time.now, updated_by: user) - # Update order_articles. Save the current article_price to keep price consistency + # Update order_articles. Save the current article_version to keep price consistency # Also save results for each group_order_result # Clean up - order_articles.includes(:article).find_each do |oa| - oa.update_attribute(:article_price, oa.article.article_prices.first) + order_articles.each do |oa| oa.group_order_articles.each do |goa| goa.save_results! - # Delete no longer required order-history (group_order_article_quantities) and - # TODO: Do we need articles, which aren't ordered? (units_to_order == 0 ?) - # A: Yes, we do - for redistributing articles when the number of articles - # delivered changes, and for statistics on popular articles. Records - # with both tolerance and quantity zero can be deleted. - # goa.group_order_article_quantities.clear end end @@ -280,9 +276,9 @@ def close!(user, transaction_type = nil, financial_link = nil, create_foodcoop_t charge_group_orders!(user, transaction_type, financial_link) if stockit? # Decreases the quantity of stock_articles - for oa in order_articles.includes(:article) + for oa in order_articles.includes(article_version: :article) oa.update_results! # Update units_to_order of order_article - stock_changes.create! stock_article: oa.article, quantity: oa.units_to_order * -1 + stock_changes.create! stock_article: oa.article_version.article, quantity: oa.units_to_order * -1 end end @@ -295,7 +291,7 @@ def close!(user, transaction_type = nil, financial_link = nil, create_foodcoop_t ft.save! end - update!(state: 'closed', updated_by: user, foodcoop_result: profit) + update! state: 'closed', updated_by: user, foodcoop_result: profit end end @@ -307,7 +303,7 @@ def close_direct!(user) comments.create(user: user, text: I18n.t('orders.model.close_direct_message')) end - update!(state: 'closed', updated_by: user) + update! state: 'closed', updated_by: user end def send_to_supplier!(user) @@ -356,23 +352,24 @@ def include_articles end def keep_ordered_articles - chosen_order_articles = order_articles.where(article_id: article_ids) + chosen_order_articles = order_articles.joins(:article_version).where(article_versions: { article_id: article_ids }) to_be_removed = order_articles - chosen_order_articles to_be_removed_but_ordered = to_be_removed.select { |a| a.quantity > 0 || a.tolerance > 0 } return if to_be_removed_but_ordered.empty? || ignore_warnings errors.add(:articles, I18n.t(stockit? ? 'orders.model.warning_ordered_stock' : 'orders.model.warning_ordered')) - @erroneous_article_ids = to_be_removed_but_ordered.map { |a| a.article_id } + @erroneous_article_ids = to_be_removed_but_ordered.map { |oa| oa.article_version.article_id } end def save_order_articles # fetch selected articles articles_list = Article.find(article_ids) # create new order_articles - (articles_list - articles).each { |article| order_articles.create(article: article) } + articles = article_versions.map(&:article) + (articles_list - articles).each { |article| order_articles.create(article_version: article.latest_article_version) } # delete old order_articles articles.reject { |article| articles_list.include?(article) }.each do |article| - order_articles.detect { |order_article| order_article.article_id == article.id }.destroy + order_articles.detect { |order_article| order_article.article_version.article_id == article.id }.destroy end end @@ -408,7 +405,7 @@ def update_price_of_group_orders! def charge_group_orders!(user, transaction_type = nil, financial_link = nil) note = transaction_note - group_orders.includes(:ordergroup).find_each do |group_order| + group_orders.includes(:ordergroup).each do |group_order| if group_order.ordergroup price = group_order.total * -1 # decrease! account balance group_order.ordergroup.add_financial_transaction!(price, note, user, transaction_type, financial_link, group_order) diff --git a/app/models/order_article.rb b/app/models/order_article.rb index 14193d155..a176675f4 100644 --- a/app/models/order_article.rb +++ b/app/models/order_article.rb @@ -5,19 +5,23 @@ class OrderArticle < ApplicationRecord attr_reader :update_global_price belongs_to :order - belongs_to :article - belongs_to :article_price, optional: true + belongs_to :article_version has_many :group_order_articles, dependent: :destroy - validates :order_id, :article_id, presence: true - validate :article_and_price_exist - validates :article_id, uniqueness: { scope: :order_id } + validates :order_id, :article_version_id, presence: true + validate :article_version_and_price_exist + validates :article_version_id, uniqueness: { scope: :order_id } _ordered_sql = 'order_articles.units_to_order > 0 OR order_articles.units_billed > 0 OR order_articles.units_received > 0' scope :ordered, -> { where(_ordered_sql) } scope :ordered_or_member, lambda { includes(:group_order_articles).where("#{_ordered_sql} OR order_articles.quantity > 0 OR group_order_articles.result > 0") } + scope :belonging_to_open_order, -> { joins(:order).merge(Order.open) } + scope :belonging_to_finished_order, -> { joins(:order).merge(Order.finished) } + + # alias for old code which is hard to automatically replace (.price could also refer to ArticleVersion.price) + alias price article_version before_create :init_from_balancing after_destroy :update_ordergroup_prices @@ -30,12 +34,6 @@ def self.ransackable_associations(_auth_object = nil) %w[order article] end - # This method returns either the ArticlePrice or the Article - # The first will be set, when the the order is finished - def price - article_price || article - end - # latest information on available units def units return units_received unless units_received.nil? @@ -48,7 +46,7 @@ def units # In balancing this can differ from ordered (by supplier) quantity for this article. def group_orders_sum quantity = group_order_articles.collect(&:result).sum - { quantity: quantity, price: quantity * price.fc_price } + { quantity: quantity, price: quantity * price.fc_group_order_price } end # Update quantity/tolerance/units_to_order from group_order_articles @@ -83,34 +81,31 @@ def update_results! # 4 | 5 | 4 | 2 # def calculate_units_to_order(quantity, tolerance = 0) - unit_size = price.unit_quantity - units = quantity / unit_size - remainder = quantity % unit_size - units += ((remainder > 0) && (remainder + tolerance >= unit_size) ? 1 : 0) + return 0 if !price.minimum_order_quantity.nil? && quantity + tolerance < price.minimum_order_quantity + return price.minimum_order_quantity if quantity > 0 && !price.minimum_order_quantity.nil? && quantity < price.minimum_order_quantity && quantity + tolerance >= price.minimum_order_quantity + + unit_size = price.convert_quantity(1, price.supplier_order_unit, price.group_order_unit) + if price.supplier_order_unit_is_si_convertible + quantity / unit_size + else + units = (quantity / unit_size).floor + remainder = quantity % unit_size + units += ((remainder > 0) && (remainder + tolerance >= unit_size) ? 1 : 0) + end end # Calculate price for ordered quantity. def total_price - units * price.unit_quantity * price.price + units * price.price end # Calculate gross price for ordered qunatity. def total_gross_price - units * price.unit_quantity * price.gross_price - end - - def ordered_quantities_different_from_group_orders?(ordered_mark = '!', billed_mark = '?', received_mark = '?') - if !units_received.nil? - (units_received * price.unit_quantity) == group_orders_sum[:quantity] ? false : received_mark - elsif !units_billed.nil? - (units_billed * price.unit_quantity) == group_orders_sum[:quantity] ? false : billed_mark - elsif !units_to_order.nil? - (units_to_order * price.unit_quantity) == group_orders_sum[:quantity] ? false : ordered_mark - end + units * price.gross_price end # redistribute articles over ordergroups - # quantity Number of units to distribute + # quantity Number of units to distribute (in group_order_unit) # surplus What to do when there are more articles than ordered quantity # :tolerance fill member orders' tolerance # :stock move to stock @@ -154,31 +149,19 @@ def redistribute(quantity, surplus = [:tolerance], update_totals = true) end # Updates order_article and belongings during balancing process - def update_article_and_price!(order_article_attributes, article_attributes, price_attributes = nil) + def update_handling_versioning!(order_article_attributes, version_attributes) OrderArticle.transaction do # Updates self update!(order_article_attributes) - # Updates article - article.update!(article_attributes) - - # Updates article_price belonging to current order article - if price_attributes.present? - article_price.attributes = price_attributes - if article_price.changed? - # Updates also price attributes of article if update_global_price is selected - if update_global_price - article.update!(price_attributes) - self.article_price = article.article_prices.first and save # Assign new created article price to order article - else - # Creates a new article_price if neccessary - # Set created_at timestamp to order ends, to make sure the current article price isn't changed - create_article_price!(price_attributes.merge(article_id: article_id, created_at: order.ends)) and save - end - - # Updates ordergroup values - update_ordergroup_prices - end + # Updates article_version belonging to current order article + original_article_version = article_version.duplicate_including_article_unit_ratios + article_version.assign_attributes(version_attributes) + if article_version.changed? + update_or_create_article_version(version_attributes, original_article_version) + + # Updates ordergroup values + update_ordergroup_prices end end end @@ -189,11 +172,13 @@ def update_global_price=(value) # @return [Number] Units missing for the last +unit_quantity+ of the article. def missing_units - _missing_units(price.unit_quantity, quantity, tolerance) + unit_ratio = price.convert_quantity(1, price.supplier_order_unit, price.group_order_unit) + _missing_units(unit_ratio, quantity, tolerance, price.minimum_order_quantity) end def missing_units_was - _missing_units(price.unit_quantity, quantity_was, tolerance_was) + unit_ratio = price.convert_quantity(1, price.supplier_order_unit, price.group_order_unit) + _missing_units(unit_ratio, quantity_was, tolerance_was, price.minimum_order_quantity) end # Check if the result of any associated GroupOrderArticle was overridden manually @@ -207,20 +192,49 @@ def difference_received_ordered private - def article_and_price_exist - if !(article = Article.find(article_id)) || article.fc_price.nil? - errors.add(:article, + def article_version_and_price_exist + if !(article_version = ArticleVersion.find(article_version_id)) || article_version.fc_price.nil? + errors.add(:article_version, I18n.t('model.order_article.error_price')) end rescue StandardError - errors.add(:article, I18n.t('model.order_article.error_price')) + errors.add(:article_version, I18n.t('model.order_article.error_price')) end # Associate with current article price if created in a finished order def init_from_balancing return unless order.present? && order.finished? - self.article_price = article.article_prices.first + self.article_version = article_version.article.article_versions.first + end + + def update_or_create_article_version(version_attributes, original_article_version) + version_attributes = version_attributes.merge(article_id: article_version.article_id) + + modifying_earlier_version = article_version.article.latest_article_version.id != article_version_id + finished_order_article_using_same_version = OrderArticle.belonging_to_finished_order.where(article_version_id: article_version_id).where.not(id: id) + + if (!update_global_price && modifying_earlier_version && !finished_order_article_using_same_version.exists?) || + (update_global_price && !modifying_earlier_version) + # update in place: + article_version.save + else + # create new version: + original_version_id = article_version.id + self.article_version = article_version.duplicate_including_article_unit_ratios + article_version.save + update_attribute(:article_version_id, article_version.id) + + if update_global_price + # update open order articles: + OrderArticle.belonging_to_open_order.where(article_version_id: original_version_id).update_all(article_version_id: article_version.id) + else + # create yet *another* version, wich contains the old data, so new orders will continue using that data: + # (The checkbox "Also update the price of future orders" not being checked implies that) + original_article_version.created_at = article_version.created_at + 1.second + original_article_version.save + end + end end def update_ordergroup_prices @@ -242,15 +256,20 @@ def enforce_boxfill unless (delta_q == 0 && delta_t >= 0) || (delta_mis < 0 && delta_box >= 0 && delta_t >= 0) || (delta_q > 0 && delta_q == -delta_t) - raise ActiveRecord::RecordNotSaved.new("Change not acceptable in boxfill phase for '#{article.name}', sorry.", + raise ActiveRecord::RecordNotSaved.new("Change not acceptable in boxfill phase for '#{article_version.name}', sorry.", self) end end - def _missing_units(unit_quantity, quantity, tolerance) - units = unit_quantity - ((quantity % unit_quantity) + tolerance) + def _missing_units(unit_ratio, quantity, tolerance, minimum_order_quantity) + return minimum_order_quantity - quantity - tolerance if !minimum_order_quantity.nil? && quantity > 0 && quantity + tolerance < minimum_order_quantity + + return 0 if article_version.supplier_order_unit_is_si_convertible + + units = unit_ratio - ((quantity % unit_ratio) + tolerance) + units = 0 if units < 0 - units = 0 if units == unit_quantity + units = 0 if units == unit_ratio units end end diff --git a/app/models/shared_article.rb b/app/models/shared_article.rb deleted file mode 100644 index 66ff2b88f..000000000 --- a/app/models/shared_article.rb +++ /dev/null @@ -1,30 +0,0 @@ -class SharedArticle < ApplicationRecord - # connect to database from sharedLists-Application - SharedArticle.establish_connection(FoodsoftConfig[:shared_lists]) - # set correct table_name in external DB - self.table_name = 'articles' - - belongs_to :shared_supplier, foreign_key: :supplier_id - - def self.ransackable_attributes(_auth_object = nil) - %w[category created_on deposit id manufacturer name note number origin price scale_price scale_quantity supplier_id tax unit unit_quantity updated_on] - end - - def build_new_article(supplier) - supplier.articles.build( - name: name, - unit: unit, - note: note, - manufacturer: manufacturer, - origin: origin, - price: price, - tax: tax, - deposit: deposit, - unit_quantity: unit_quantity, - order_number: number, - article_category: ArticleCategory.find_match(category), - # convert to db-compatible-string - shared_updated_on: updated_on.to_fs(:db) - ) - end -end diff --git a/app/models/shared_supplier.rb b/app/models/shared_supplier.rb deleted file mode 100644 index e2b23805c..000000000 --- a/app/models/shared_supplier.rb +++ /dev/null @@ -1,36 +0,0 @@ -class SharedSupplier < ApplicationRecord - # connect to database from sharedLists-Application - SharedSupplier.establish_connection(FoodsoftConfig[:shared_lists]) - # set correct table_name in external DB - self.table_name = 'suppliers' - - has_many :suppliers, -> { undeleted } - has_many :shared_articles, foreign_key: :supplier_id - - def find_article_by_number(order_number) - # NOTE: that `shared_articles` uses number instead order_number - cached_articles.detect { |a| a.number == order_number } - end - - def cached_articles - @cached_articles ||= shared_articles.all - end - - # These set of attributes are used to autofill attributes of new supplier, - # when created by import from shared supplier feature. - def autofill_attributes - whitelist = %w[name address phone fax email url delivery_days note] - attributes.select { |k, _v| whitelist.include?(k) } - end - - # return list of synchronisation methods available for this supplier - def shared_sync_methods - methods = [] - if shared_articles.count < FoodsoftConfig[:shared_supplier_article_sync_limit] - methods += %w[all_available - all_unavailable] - end - methods += %w[import] - methods - end -end diff --git a/app/models/stock_article.rb b/app/models/stock_article.rb index 14b8d5ef5..30c5b0790 100644 --- a/app/models/stock_article.rb +++ b/app/models/stock_article.rb @@ -1,7 +1,7 @@ class StockArticle < Article has_many :stock_changes - scope :available, -> { undeleted.where('quantity > 0') } + scope :available, -> { undeleted.with_latest_versions_and_categories.where('quantity > 0') } validates :quantity, presence: true, numericality: { greater_than_or_equal_to: 0 } @@ -28,8 +28,8 @@ def quantity_available end def quantity_ordered - OrderArticle.where(article_id: id) - .joins(:order).where(orders: { state: %w[open finished received] }).sum(:units_to_order) + OrderArticle.joins(:order, :article_version).where(article_versions: { article_id: id }) + .where(orders: { state: %w[open finished received] }).sum(:units_to_order) end def quantity_history diff --git a/app/models/supplier.rb b/app/models/supplier.rb index 56999be1d..ae3ae36e6 100644 --- a/app/models/supplier.rb +++ b/app/models/supplier.rb @@ -1,16 +1,19 @@ +require 'net/http' + class Supplier < ApplicationRecord include MarkAsDeletedWithName include CustomFields has_many :articles, lambda { - where(type: nil).includes(:article_category).order('article_categories.name', 'articles.name') + merge(Article.not_in_stock.with_latest_versions_and_categories.order('article_categories.name, article_versions.name')) } - has_many :stock_articles, -> { includes(:article_category).order('article_categories.name', 'articles.name') } + has_many :stock_articles, lambda { + merge(StockArticle.with_latest_versions_and_categories.order('article_categories.name, article_versions.name')) + } has_many :orders has_many :deliveries has_many :invoices belongs_to :supplier_category - belongs_to :shared_supplier, optional: true # for the sharedLists-App validates :name, presence: true, length: { in: 4..30 } validates :phone, presence: true, length: { in: 8..25 } @@ -18,8 +21,12 @@ class Supplier < ApplicationRecord validates :iban, format: { with: /\A[A-Z]{2}[0-9]{2}[0-9A-Z]{,30}\z/, allow_blank: true } validates :iban, uniqueness: { case_sensitive: false, allow_blank: true } validates :order_howto, :note, length: { maximum: 250 } - validate :valid_shared_sync_method validate :uniqueness_of_name + validates :shared_sync_method, presence: true, unless: -> { supplier_remote_source.blank? } + validates :shared_sync_method, absence: true, if: -> { supplier_remote_source.blank? } + validates :supplier_remote_source, format: { with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true } + + enum shared_sync_method: { all_available: 'all_available', all_unavailable: 'all_unavailable', import: 'import' } scope :undeleted, -> { where(deleted_at: nil) } scope :having_articles, -> { where(id: Article.undeleted.select(:supplier_id).distinct) } @@ -32,46 +39,6 @@ def self.ransackable_associations(_auth_object = nil) %w[articles stock_articles orders] end - # sync all articles with the external database - # returns an array with articles(and prices), which should be updated (to use in a form) - # also returns an array with outlisted_articles, which should be deleted - # also returns an array with new articles, which should be added (depending on shared_sync_method) - def sync_all - updated_article_pairs = [] - outlisted_articles = [] - new_articles = [] - existing_articles = Set.new - for article in articles.undeleted - # try to find the associated shared_article - shared_article = article.shared_article(self) - - if shared_article # article will be updated - existing_articles.add(shared_article.id) - unequal_attributes = article.shared_article_changed?(self) - if unequal_attributes.present? # skip if shared_article has not been changed - article.attributes = unequal_attributes - updated_article_pairs << [article, unequal_attributes] - end - # Articles with no order number can be used to put non-shared articles - # in a shared supplier, with sync keeping them. - elsif article.order_number.present? - # article isn't in external database anymore - outlisted_articles << article - end - end - # Find any new articles, unless the import is manual - if %w[all_available all_unavailable].include?(shared_sync_method) - # build new articles - shared_supplier - .shared_articles - .where.not(id: existing_articles.to_a) - .find_each { |new_shared_article| new_articles << new_shared_article.build_new_article(self) } - # make them unavailable when desired - new_articles.each { |new_article| new_article.availability = false } if shared_sync_method == 'all_unavailable' - end - [updated_article_pairs, outlisted_articles, new_articles] - end - # Synchronise articles with spreadsheet. # # @param file [File] Spreadsheet file to parse @@ -79,46 +46,28 @@ def sync_all # @option options [Boolean] :outlist_absent Set to +true+ to remove articles not in spreadsheet. # @option options [Boolean] :convert_units Omit or set to +true+ to keep current units, recomputing unit quantity and price. def sync_from_file(file, options = {}) - all_order_numbers = [] - updated_article_pairs = [] - outlisted_articles = [] - new_articles = [] - FoodsoftFile.parse file, options do |status, new_attrs, line| - article = articles.undeleted.where(order_number: new_attrs[:order_number]).first - new_attrs[:article_category] = ArticleCategory.find_match(new_attrs[:article_category]) - new_attrs[:tax] ||= FoodsoftConfig[:tax_default] - new_article = articles.build(new_attrs) - - if status.nil? - if article.nil? - new_articles << new_article - else - unequal_attributes = article.unequal_attributes(new_article, options.slice(:convert_units)) - unless unequal_attributes.empty? - article.attributes = unequal_attributes - updated_article_pairs << [article, unequal_attributes] - end - end - elsif status == :outlisted && article.present? - outlisted_articles << article - - # stop when there is a parsing error - elsif status.is_a? String - # @todo move I18n key to model - raise I18n.t('articles.model.error_parse', msg: status, line: line.to_s) - end - - all_order_numbers << article.order_number if article + data = FoodsoftFile.parse(file, options) + data.each do |new_attrs| + new_article = foodsoft_file_attrs_to_article(new_attrs.dup) + new_attrs[:price] = new_attrs[:price].to_d / new_article.convert_quantity(1, new_article.price_unit, new_article.supplier_order_unit) end - outlisted_articles += articles.undeleted.where.not(order_number: all_order_numbers + [nil]) if options[:outlist_absent] - [updated_article_pairs, outlisted_articles, new_articles] + parse_import_data({ articles: data }, options) + [data] end - # default value - def shared_sync_method - return unless shared_supplier + def read_from_remote(search_params = {}) + url = URI(supplier_remote_source) + url.query = URI.encode_www_form(search_params) unless search_params.nil? + http = Net::HTTP.new(url.host, url.port) + http.use_ssl = url.scheme == 'https' + request = Net::HTTP::Get.new(url) + + response = http.request(request) + JSON.parse(response.body, symbolize_names: true) + end - self[:shared_sync_method] || 'import' + def sync_from_remote(options = {}) + data = read_from_remote(options[:search_params]) + parse_import_data(data, options) + [data] end def deleted? @@ -133,20 +82,30 @@ def mark_as_deleted end end - # @return [Boolean] Whether there are articles that would use tolerance (unit_quantity > 1) + # @return [Boolean] Whether there are articles that would use tolerance def has_tolerance? - articles.where('articles.unit_quantity > 1').any? + articles.with_latest_versions_and_categories.any? { |article| article.latest_article_version.uses_tolerance? } end - protected - - # make sure the shared_sync_method is allowed for the shared supplier - def valid_shared_sync_method - return unless shared_supplier && !shared_supplier.shared_sync_methods.include?(shared_sync_method) + # TODO: Maybe use the `nilify_blanks` gem instead of the following two methods? (see https://github.com/foodcoopsat/foodsoft_hackathon/issues/93): + def supplier_remote_source=(value) + if value.blank? + self[:supplier_remote_source] = nil + else + super + end + end - errors.add :shared_sync_method, :included + def shared_sync_method=(value) + if value.blank? + self[:shared_sync_method] = nil + else + super + end end + protected + # Make sure, the name is uniq, add usefull message if uniq group is already deleted def uniqueness_of_name supplier = Supplier.where(name: name) @@ -156,4 +115,52 @@ def uniqueness_of_name message = supplier.first.deleted? ? :taken_with_deleted : :taken errors.add :name, message end + + def parse_import_data(data, options = {}) + all_order_numbers = [] + updated_article_pairs = [] + outlisted_articles = [] + new_articles = [] + + data[:articles].each do |new_attrs| + article = articles.includes(:latest_article_version).undeleted.where(article_versions: { order_number: new_attrs[:order_number] }).first + new_article = foodsoft_file_attrs_to_article(new_attrs) + + if new_attrs[:availability] + if article.nil? + new_articles << new_article + else + unequal_attributes = article.unequal_attributes(new_article, options.slice(:convert_units)) + unless unequal_attributes.empty? + article.latest_article_version.article_unit_ratios.target.clear unless unequal_attributes[:article_unit_ratios_attributes].nil? + article.latest_article_version.attributes = unequal_attributes + duped_ratios = article.latest_article_version.article_unit_ratios.map(&:dup) + article.latest_article_version.article_unit_ratios.target.clear + article.latest_article_version.article_unit_ratios.target.push(*duped_ratios) + updated_article_pairs << [article, unequal_attributes] + end + end + elsif article.present? + outlisted_articles << article + end + all_order_numbers << article.order_number if article + end + outlisted_articles += articles.includes(:latest_article_version).undeleted.where.not(article_versions: { order_number: all_order_numbers + [nil] }) if options[:outlist_absent] + [updated_article_pairs, outlisted_articles, new_articles] + end + + def foodsoft_file_attrs_to_article(foodsoft_file_attrs) + foodsoft_file_attrs = foodsoft_file_attrs.dup + foodsoft_file_attrs[:article_category] = ArticleCategory.find_match(foodsoft_file_attrs[:article_category]) + foodsoft_file_attrs[:tax] ||= FoodsoftConfig[:tax_default] + foodsoft_file_attrs[:article_unit_ratios] = foodsoft_file_attrs[:article_unit_ratios].map do |ratio_hash| + ArticleUnitRatio.new(ratio_hash) + end + new_article = articles.build + new_article_version = new_article.article_versions.build(foodsoft_file_attrs) + new_article.article_versions << new_article_version + new_article.latest_article_version = new_article_version + + new_article + end end diff --git a/app/serializers/article_unit_serializer.rb b/app/serializers/article_unit_serializer.rb new file mode 100644 index 000000000..9f1dffc78 --- /dev/null +++ b/app/serializers/article_unit_serializer.rb @@ -0,0 +1,3 @@ +class ArticleUnitSerializer < ActiveModel::Serializer + attributes :id, :unit +end diff --git a/app/serializers/order_article_serializer.rb b/app/serializers/order_article_serializer.rb index 10de058f5..713dc0bc4 100644 --- a/app/serializers/order_article_serializer.rb +++ b/app/serializers/order_article_serializer.rb @@ -2,9 +2,9 @@ class OrderArticleSerializer < ActiveModel::Serializer attributes :id, :order_id, :price attributes :quantity, :tolerance, :units_to_order - has_one :article + has_one :article_version def price - object.price.fc_price.to_f + object.article_version.fc_price.to_f end end diff --git a/app/views/article_units/_create_link.html.haml b/app/views/article_units/_create_link.html.haml new file mode 100644 index 000000000..83f743a6e --- /dev/null +++ b/app/views/article_units/_create_link.html.haml @@ -0,0 +1 @@ += link_to t('.add'), article_units_path(unit: unit), class: 'btn btn-mini', remote: true, method: :post, data: {'for-unit': unit, 'e2e-create-unit': unit} diff --git a/app/views/article_units/_destroy_link.html.haml b/app/views/article_units/_destroy_link.html.haml new file mode 100644 index 000000000..2913873d4 --- /dev/null +++ b/app/views/article_units/_destroy_link.html.haml @@ -0,0 +1 @@ +=link_to t('.delete'), article_unit, method: :delete, class: 'btn btn-mini btn-danger', remote: true, data: { confirm: t('.confirm'), 'for-unit': article_unit.unit, 'e2e-destroy-unit': article_unit.unit } diff --git a/app/views/article_units/_rows.html.haml b/app/views/article_units/_rows.html.haml new file mode 100644 index 000000000..8b9792052 --- /dev/null +++ b/app/views/article_units/_rows.html.haml @@ -0,0 +1,16 @@ +- @article_units.each do |article_unit| + %tr{class: ("untranslated" if article_unit[:untranslated])} + %td= article_unit[:code] + %td= highlight(article_unit[:symbol], @query) + %td + = highlight(article_unit[:name], @query) + - if article_unit[:untranslated] + %a{title: t('.request_translation'), href: "https://github.com/foodcoops/foodsoft/issues/new?title=Add%20translations%20for%20article%20unit%20%27#{article_unit[:code]}%27", target: '_blank'} + %i.icon-mail-forward + %td= article_unit[:description] + %td + - if article_unit[:record].nil? + = render partial: 'create_link', locals: {unit: article_unit[:code]} + - else + = render partial: 'destroy_link', locals: {article_unit: article_unit[:record]} + diff --git a/app/views/article_units/create.js.haml b/app/views/article_units/create.js.haml new file mode 100644 index 000000000..18eccd4e4 --- /dev/null +++ b/app/views/article_units/create.js.haml @@ -0,0 +1,2 @@ +$('div.container-fluid').prepend('#{j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.success', name: @available_units[@article_unit.unit][:name])}))}') +$('a[data-for-unit="#{@article_unit.unit}"]').replaceWith('#{j(render(partial: "destroy_link", locals: {article_unit: @article_unit}))}') diff --git a/app/views/article_units/destroy.js.haml b/app/views/article_units/destroy.js.haml new file mode 100644 index 000000000..98d446d09 --- /dev/null +++ b/app/views/article_units/destroy.js.haml @@ -0,0 +1,2 @@ +$('div.container-fluid').prepend('#{j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.success', name: @available_units[@article_unit.unit][:name])}))}') +$('a[data-for-unit="#{@article_unit.unit}"]').replaceWith('#{j(render(partial: "create_link", locals: {unit: @article_unit.unit}))}') diff --git a/app/views/article_units/index.html.haml b/app/views/article_units/index.html.haml new file mode 100644 index 000000000..474880ed8 --- /dev/null +++ b/app/views/article_units/index.html.haml @@ -0,0 +1,60 @@ +=form_with url: search_article_units_path, method: :get, id: :article_unit_search_form, html: {'data-remote': true} do |form| + .d-flex.align-items-center + = form.text_field :q, id: :article_unit_search, placeholder: t('.search'), class: 'm-0' + = form.check_box :only_recommended, id: :only_recommended, class: 'm-0 ml-2', checked: true + = form.label :only_recommended, t('.only_recommended'), class: 'm-0 ml-1', for: :only_recommended + +%table.table.table-striped + %thead + %tr + %th= heading_helper ArticleUnit, :code, short: true + %th= heading_helper ArticleUnit, :symbol + %th= heading_helper ArticleUnit, :name + %th= heading_helper ArticleUnit, :description + %th + %th + + %tbody#article_units_search_results +%br + + +- content_for :javascript do + :javascript + let timer; + function debounce(timeout, func){ + return (...args) => { + if (timer !== undefined) { + clearTimeout(timer); + timer = undefined; + } + timer = setTimeout(() => { + func.apply(this, args); + }, timeout); + }; + } + + $(document).ready(function () { + $('#article_unit_search, #only_recommended').on('input', debounce(250, () => { + $('#article_unit_search_form').submit(); + })); + }); + + let currentXhr; + + $(document).on('ajax:send', function(_event, xhr) { + if (timer !== undefined) { + clearTimeout(timer); + timer = undefined; + } + if (currentXhr) { + currentXhr.abort(); + } + currentXhr = xhr; + return true; + }); + + $(document).on('ajax:complete', function(_event, _xhr, _status) { + currentXhr = null; + }); + + $('#article_unit_search_form').submit(); diff --git a/app/views/article_units/search.js.haml b/app/views/article_units/search.js.haml new file mode 100644 index 000000000..6ef276a79 --- /dev/null +++ b/app/views/article_units/search.js.haml @@ -0,0 +1 @@ +$('#article_units_search_results').html('#{j(render("rows"))}'); diff --git a/app/views/articles/_article.html.haml b/app/views/articles/_article.html.haml index 33d753d75..4be6f6982 100644 --- a/app/views/articles/_article.html.haml +++ b/app/views/articles/_article.html.haml @@ -3,9 +3,9 @@ %td{'data-check-this' => "#checkbox_#{article.id}", :class => 'click-me'}= article.name %td= article.origin %td= truncate(article.article_category.name, :length => 11) if article.article_category - %td= article.unit + %td= format_group_order_unit_with_ratios(article) %td= truncate(article.note, :length => 11) - %td= article.unit_quantity + %td= format_supplier_order_unit_with_ratios(article) %td{:class => "currency"} %acronym{:title => t('.last_update', last_update: format_date(article.updated_at), gross_price: number_to_currency(article.gross_price))} = number_to_currency(article.price) @@ -13,7 +13,7 @@ %td= number_to_currency(article.deposit) if article.deposit != 0 %td = link_to t('ui.edit'), edit_supplier_article_path(@supplier, article), - remote: true, class: 'btn btn-mini' + remote: true, class: 'btn btn-mini', data: {'e2e-edit-article': article.id} = link_to t('ui.copy'), supplier_article_copy_path(@supplier, article), remote: true, class: 'btn btn-mini' = link_to t('ui.delete'), [@supplier, article], diff --git a/app/views/articles/_edit_all_table.html.haml b/app/views/articles/_edit_all_table.html.haml index e77527926..14bda1a93 100644 --- a/app/views/articles/_edit_all_table.html.haml +++ b/app/views/articles/_edit_all_table.html.haml @@ -1,11 +1,21 @@ +- content_for :javascript do + :javascript + const units = #{raw(@all_units.to_json)}; +- content_for :javascript do + = simple_fields_for "articles[TEMPLATEREPLACEMARKER]" do |form| + :javascript + const ratioTemplateHtml = "#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: form, article_unit_ratio_counter: -1}))}"; +- price_markup = FoodsoftConfig[:price_markup].to_f += render partial: 'shared/js_templates/unit_conversion_popover_template' %table.table %thead %tr %th= heading_helper Article, :availability, short: true %th= heading_helper Article, :name + - unless @original_units.nil? + %th= heading_helper Article, :original_unit %th= heading_helper Article, :unit %th= heading_helper Article, :price, short: true - %th= heading_helper Article, :unit_quantity, short: true %th= heading_helper Article, :order_number, short: true %th= heading_helper Article, :note %th= heading_helper Article, :article_category @@ -13,18 +23,55 @@ %th= heading_helper Article, :deposit %tbody - @articles.each_with_index do |article, index| - = fields_for "articles[#{article.id || index}]", article do |form| - %tr + %tr{:id => "article_row_#{article.id}"} + = simple_fields_for "articles[#{article.id}]", article.latest_article_version do |form| %td = yield form # allow to add hidden fields to form = form.check_box 'availability' %td= form.text_field 'name', class: 'input-medium' - %td= form.text_field 'unit', class: 'input-mini' - %td= form.text_field 'price', class: 'input-mini' - %td= form.text_field 'unit_quantity', class: 'input-mini' + - unless @original_units.nil? + %td + = "\"#{@original_units[article.id]}\"" unless @original_units[article.id].blank? + %td + .d-flex.gap-1.align-items-center + = form.hidden_field :unit, id: 'article_unit_hidden', value: '' + = form.input :supplier_order_unit, as: :select, collection: @article_units, label: false, value: article.supplier_order_unit, include_blank: t('.custom_unit'), input_html: {class: 'input-medium'} + = form.input :unit, input_html: {class: 'input-mini ml-1'}, label: false + %div.btn-link.toggle-extra-units.text-decoration-none.default-values + %i.icon-cog + %div.extra-unit-fields.form-horizontal + .fold-line + .control-group + %label.control-label{for: 'unit_ratios'} + = "Unit ratios" + %table#fc_base_price{:class => "controls"} + %tbody + - ratios = article.article_unit_ratios + = render :partial => 'shared/article_unit_ratio', :as => 'article_unit_ratio', :collection => ratios, locals: {f: form, original_ratios: article&.article_unit_ratios} + %tfoot + %tr + %td{:colspan => 6} + = link_to t('.add_ratio'), '#', 'data-add-ratio' => true, class: 'btn', title: t(".add_ratio") + .fold-line + = form.input :minimum_order_quantity, label: "Mininum order quantity" do + .input-append + = form.input_field :minimum_order_quantity, class: 'input-mini', title: "total minimum order quantity for this article" + .fold-line + = form.input :billing_unit, as: :select, collection: [], input_html: {'data-initial-value': article.billing_unit, class: 'input-medium'}, include_blank: false + .fold-line + = form.input :group_order_granularity, label: "Allow orders per", input_html: {class: 'input-mini', title: "steps in which ordergroups can order this article"} + = form.input :group_order_unit, as: :select, collection: [], input_html: {'data-initial-value': article.group_order_unit, class: 'input-medium'}, label: '×'.html_safe, include_blank: false + %td + .d-flex.gap-1 + .input-prepend + %span.add-on= t 'number.currency.format.unit' + = form.text_field 'price', class: 'input-mini', style: 'width: 45px' + .input.d-flex.gap-1.control-group + %label=t('articles.form.per') + = form.input :price_unit, as: :select, collection: [], input_html: {'data-initial-value': article.price_unit, class: 'input-medium'}, label: false, wrapper: false, include_blank: false %td= form.text_field 'order_number', class: 'input-mini' %td= form.text_field 'note', class: 'input-medium' - %td= form.collection_select 'article_category_id', ArticleCategory.all, + %td= form.collection_select 'article_category_id', @article_categories, :id, :name, { :include_blank => true }, class: 'input-small' %td.input-append = form.text_field 'tax', class: 'input-mini' @@ -33,3 +80,11 @@ - unless article.errors.empty? %tr.alert %td(colspan="10")= article.errors.full_messages.join(", ") +- content_for :javascript do + - @articles.each_with_index do |article, index| + :javascript + articleUnitRatioTemplate$ = $($.parseHTML(ratioTemplateHtml.replace(/TEMPLATEREPLACEMARKER/g, '#{article.id}'))); + new ArticleForm(articleUnitRatioTemplate$, $('#article_row_#{article.id}'), units, #{price_markup}, $('#article_row_#{article.id}').closest('form'), 'articles_#{article.id}', 'articles[#{article.id}]'); + - if index + 1 === @articles.length + :javascript + $('input[name="commit"]').removeAttr('disabled'); diff --git a/app/views/articles/_form.html.haml b/app/views/articles/_form.html.haml index 7cbd64cd8..029a5d9fd 100644 --- a/app/views/articles/_form.html.haml +++ b/app/views/articles/_form.html.haml @@ -1,24 +1,29 @@ -= simple_form_for [@supplier, @article], :validate => true, :remote => true do |f| - = f.hidden_field :shared_updated_on - = f.hidden_field :supplier_id +- url = @article.new_record? ? supplier_articles_path(@supplier, @article, foodcoop: FoodsoftConfig.scope) : supplier_article_path(@supplier, @article) += simple_form_for [@supplier, @article.latest_article_version], :url => url, :validate => true, :remote => true do |f| + :javascript + const articleUnitRatioTemplate$ = $($.parseHTML("#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: f, article_unit_ratio_counter: -1}))}")); + const units = #{raw(@all_units.to_json)}; + new ArticleForm(articleUnitRatioTemplate$, $('.article-form').parents('form'), units, #{FoodsoftConfig[:price_markup].to_f}); + + = render partial: 'shared/js_templates/unit_conversion_popover_template' .modal-header = close_button :modal %h3= @article.new_record? ? t('.title_new') : t('.title_edit') - .modal-body + .modal-body.article-form + = f.hidden_field :id = f.input :availability = f.input :name - = render partial: 'shared/article_fields_units', locals: {f: f} + = render partial: 'shared/article_fields_units', locals: {f: f, article: @article} + + = render partial: 'shared/article_fields_price', locals: {f: f, article: @article} = f.input :note = f.association :article_category / TODO labels - - = render partial: 'shared/article_fields_price', locals: {f: f} - = f.input :origin = f.input :manufacturer = f.input :order_number .modal-footer = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'} - = f.submit class: 'btn btn-primary' + = f.submit class: 'btn btn-primary', disabled: true diff --git a/app/views/articles/_import_article_added.js.erb b/app/views/articles/_import_article_added.js.erb deleted file mode 100644 index 6007213fe..000000000 --- a/app/views/articles/_import_article_added.js.erb +++ /dev/null @@ -1,4 +0,0 @@ -// update shared article button on create, so that the article will be shown as imported -// reloading the list doesn't work because it breaks paging :( -$('#shared_article_<%= article.shared_article.id %> .actions') - .html('<%= j content_tag(:i, I18n.t('articles.import_search_results.already_imported'), class: 'icon-ok')%>'); diff --git a/app/views/articles/_import_search_results.haml b/app/views/articles/_import_search_results.haml deleted file mode 100644 index c5dd56f2d..000000000 --- a/app/views/articles/_import_search_results.haml +++ /dev/null @@ -1,33 +0,0 @@ -- if @articles.empty? - %p= t '.not_found' -- else - = pagination_links_remote @articles - %table.table.table-striped - %thead - %tr - %th= heading_helper Article, :name - %th= heading_helper Article, :origin - %th= heading_helper Article, :manufacturer - %th= heading_helper Article, :note - %th{:style => "width:4em"}= heading_helper Article, :price - %th= heading_helper Article, :unit - %th - %tbody - - for article in @articles - %tr{id: "shared_article_#{article.id}"} - %td= highlight article.name, params.fetch(:name_cont_all_joined, '').split(' ') - %td= article.origin - %td= article.manufacturer - %td{title: article.note}= truncate(article.note, length: 11) - %td= number_to_currency(article.price) - %td - = article.unit - - if article.unit_quantity > 1 - %span{style: 'color: grey'} × #{article.unit_quantity} #{pkg_helper_icon} - %td.actions - - logger.debug "[debug] #{article.attributes.inspect}" - - if @supplier.articles.undeleted.where(order_number: article.number).exists? - %i.icon-ok= t '.already_imported' - - else - = link_to t('.action_import'), import_supplier_articles_path(@supplier, shared_article_id: article.id, direct: true), - remote: true, class: 'btn btn-small btn-success' diff --git a/app/views/articles/_sync.html.haml b/app/views/articles/_sync.html.haml index 05945112f..1de758aaa 100644 --- a/app/views/articles/_sync.html.haml +++ b/app/views/articles/_sync.html.haml @@ -1,11 +1,15 @@ +- content_for :javascript do + :javascript + const units = #{raw(@all_units.to_json)}; + let articleUnitRatioTemplate$ = undefined; - if @outlisted_articles.any? %h2= t '.outlist.title' %p = t('.outlist.body').html_safe %ul - - for article in @outlisted_articles + - @outlisted_articles.each_with_index do |article, index| %li - = hidden_field_tag "outlisted_articles[#{article.id}]", '1' + = hidden_field_tag "outlisted_articles[#{index}]", article.id = article.name - if article.in_open_order .alert= t '.outlist.alert_used', article: article.name @@ -17,14 +21,14 @@ %i = t '.update.update_msg', count: @updated_article_pairs.size = t '.update.body' - = render 'sync_table', articles: @updated_article_pairs, field: 'articles', hidden_fields: %w(shared_updated_on) + = render 'sync_table', articles: @updated_article_pairs, field: 'articles', hidden_fields: [] %hr/ - if @new_articles.any? %h2= t '.upnew.title' %p %i= t '.upnew.body_count', count: @new_articles.length - = render 'sync_table', articles: @new_articles, field: 'new_articles', hidden_fields: %w(shared_updated_on order_number availability) + = render 'sync_table', articles: @new_articles, field: 'new_articles', hidden_fields: %w(order_number availability) %hr/ - if ignored_article_count > 0 diff --git a/app/views/articles/_sync_table.html.haml b/app/views/articles/_sync_table.html.haml index ac17adfaf..7d47a139a 100644 --- a/app/views/articles/_sync_table.html.haml +++ b/app/views/articles/_sync_table.html.haml @@ -1,18 +1,19 @@ -%table.table +- price_markup = FoodsoftConfig[:price_markup].to_f +%table.table.sync-table %thead %tr %th= heading_helper Article, :name %th= heading_helper Article, :note %th= heading_helper Article, :manufacturer %th= heading_helper Article, :origin - %th= heading_helper Article, :unit - %th= heading_helper Article, :unit_quantity, short: true + %th= heading_helper Article, :supplier_order_unit %th= heading_helper Article, :price %th= heading_helper Article, :tax %th= heading_helper Article, :deposit %th= heading_helper Article, :article_category %tbody - - articles.each do |changed_article, attrs| + - articles.each_with_index do |data, index| + - changed_article, attrs = data - unless changed_article.new_record? - article = Article.find(changed_article.id) %tr{:style => 'color:grey'} @@ -20,27 +21,74 @@ %td= article.note %td= article.manufacturer %td= article.origin - %td= article.unit - %td= article.unit_quantity - %td= number_to_currency article.price + %td= ArticleUnitsLib.get_translated_name_for_code(article.supplier_order_unit) + %td= "#{number_to_currency(article.price_unit_price)} #{t('articles.form.per')} #{format_price_unit(article)}" %td= number_to_percentage article.tax %td= number_to_currency article.deposit %td= article.article_category.name if article.article_category - %tr - = fields_for "#{field}[]", changed_article do |form| + %tr{:id => "article_row_#{field}_#{index}"} + = render partial: 'shared/js_templates/unit_conversion_popover_template' + = simple_fields_for "#{field}[#{index}]", changed_article.latest_article_version do |form| + - content_for :javascript do + :javascript + articleUnitRatioTemplate$ = $($.parseHTML("#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: form, article_unit_ratio_counter: -1}))}")); + new ArticleForm(articleUnitRatioTemplate$, $('#article_row_#{field}_#{index}'), units, #{price_markup}, $('#article_row_#{field}_#{index}').closest('form'), '#{field}_#{index}', '#{field}[#{index}]'); %td{:style => highlight_new(attrs, :name)} = form.text_field 'name', :size => 0 + = form.input :id, as: :hidden unless changed_article.new_record? - hidden_fields.each do |field| - = form.hidden_field field + = form.input field, as: :hidden %td{:style => highlight_new(attrs, :note)}= form.text_field 'note', class: 'input-small' %td{:style => highlight_new(attrs, :manufacturer)}= form.text_field 'manufacturer', class: 'input-small' %td{:style => highlight_new(attrs, :origin)}= form.text_field 'origin', class: 'input-mini' - %td{:style => highlight_new(attrs, :unit)}= form.text_field 'unit', class: 'input-mini' - %td{:style => highlight_new(attrs, :unit_quantity)}= form.text_field 'unit_quantity', class: 'input-mini' + %td{:style => highlight_new(attrs, :supplier_order_unit)} + .d-flex.gap-1.align-items-center + = form.input :supplier_order_unit, as: :select, collection: @article_units, label: false, value: changed_article.supplier_order_unit, include_blank: t('.custom_unit'), input_html: {class: 'input-medium'} + = form.input :unit, input_html: {class: 'input-mini ml-1'}, label: false + %div.btn-link.toggle-extra-units.text-decoration-none.default-values + %i.icon-cog{:style => highlight_new(attrs, [:article_unit_ratio_attributes, :minimum_order_quantity, :billing_unit, :group_order_unit, :group_order_granularity])} + %div.extra-unit-fields.form-horizontal + .fold-line + .control-group + %label.control-label{for: 'unit_ratios'} + = "Unit ratios" + %table#fc_base_price{:class => "controls"} + %tbody + - ratios = changed_article.article_unit_ratios + = render :partial => 'shared/article_unit_ratio', :as => 'article_unit_ratio', :collection => ratios, locals: {f: form, original_ratios: article&.article_unit_ratios} + %tfoot + %tr + %td{:colspan => 6} + = link_to t('.add_ratio'), '#', 'data-add-ratio' => true, class: 'btn', title: "add ratio" + - unless changed_article.new_record? + %tr{style: 'color: grey;'} + %td{:colspan => 6} + %ul + - article.article_unit_ratios.each do |ratio| + %li + = "#{ratio.quantity} x #{ArticleUnitsLib.get_translated_name_for_code(ratio.unit)}" + = t 'articles.form.per' + = ArticleUnitsLib.get_translated_name_for_code(article.supplier_order_unit) + .fold-line + = form.input :minimum_order_quantity, label: "Mininum order quantity" do + .input-append + = form.input_field :minimum_order_quantity, class: 'input-mini', style: highlight_new(attrs, :minimum_order_quantity), title: "total minimum order quantity for this article" + %span.add-on + - unless changed_article.new_record? + %p.help-block{style: 'color: grey;'}=article.minimum_order_quantity.to_s + .fold-line + = form.input :billing_unit, hint: changed_article.new_record? ? nil : ArticleUnitsLib.get_translated_name_for_code(article.billing_unit || article.supplier_order_unit), hint_html: {style: 'color: grey;'}, as: :select, collection: [], input_html: {'data-initial-value': changed_article.billing_unit, class: 'input-medium', style: highlight_new(attrs, :billing_unit)}, include_blank: false + .fold-line + = form.input :group_order_granularity, hint: changed_article.new_record? ? nil : "#{article.group_order_granularity} x #{ArticleUnitsLib.get_translated_name_for_code(article.group_order_unit)}", hint_html: {style: 'color: grey;'}, label: "Allow orders per", input_html: {class: 'input-mini', style: highlight_new(attrs, :group_order_granularity), title: "steps in which ordergroups can order this article"} + = form.input :group_order_unit, as: :select, collection: [], input_html: {'data-initial-value': changed_article.group_order_unit, class: 'input-medium', style: highlight_new(attrs, :group_order_unit)}, label: '×'.html_safe, include_blank: false %td{:style => highlight_new(attrs, :price)} - .input-prepend - %span.add-on= t 'number.currency.format.unit' - = form.text_field 'price', class: 'input-mini', style: 'width: 45px' + .d-flex.gap-1 + .input-prepend + %span.add-on= t 'number.currency.format.unit' + = form.text_field 'price', class: 'input-mini', style: 'width: 45px' + .input.d-flex.gap-1 + %label=t('articles.form.per') + = form.select :price_unit, [], {include_blank: false}, {'data-initial-value': changed_article.price_unit, class: 'input-medium'} %td{:style => highlight_new(attrs, :tax)} .input-append = form.text_field 'tax', class: 'input-mini', style: 'width: 45px' diff --git a/app/views/articles/create.js.haml b/app/views/articles/create.js.haml index 3d8be65f9..7fa89fe96 100644 --- a/app/views/articles/create.js.haml +++ b/app/views/articles/create.js.haml @@ -1,3 +1,6 @@ $('#modalContainer').modal('hide'); $('#listbody').prepend('#{escape_javascript(render(@article))}'); +const importActionsCell$ = $('#import #search_results td[data-order-number="#{escape_javascript(@article.order_number)}"]'); +importActionsCell$.find('.icon-ok').show(); +importActionsCell$.find('.article_import_btn').hide(); = render 'import_article_added', article: @article if @article.shared_article diff --git a/app/views/articles/destroy.js.haml b/app/views/articles/destroy.js.haml index da7c5a629..1bb7588f1 100644 --- a/app/views/articles/destroy.js.haml +++ b/app/views/articles/destroy.js.haml @@ -2,3 +2,6 @@ $('#article_#{@article.id}').after('#{escape_javascript(render("destroy_active_article"))}'); - else $('#article_#{@article.id}').remove(); + const importActionsCell$ = $('#import #search_results td[data-order-number="#{escape_javascript(@article.order_number)}"]'); + importActionsCell$.find('.icon-ok').hide(); + importActionsCell$.find('.article_import_btn').show(); diff --git a/app/views/articles/edit.html.haml b/app/views/articles/edit.html.haml new file mode 100644 index 000000000..fec1326e1 --- /dev/null +++ b/app/views/articles/edit.html.haml @@ -0,0 +1,2 @@ + +=render("form") \ No newline at end of file diff --git a/app/views/articles/edit_all.html.haml b/app/views/articles/edit_all.html.haml index ec8652957..35db75158 100644 --- a/app/views/articles/edit_all.html.haml +++ b/app/views/articles/edit_all.html.haml @@ -3,8 +3,9 @@ %i= t '.note' = form_tag(update_all_supplier_articles_path(@supplier)) do = render 'edit_all_table' + = hidden_field_tag :complete_migration, true unless @original_units.nil? %br/ %i= t '.warning' .form-actions - = submit_tag t('.submit'), class: 'btn btn-primary' + = submit_tag t('.submit'), class: 'btn btn-primary', disabled: true = link_to t('ui.or_cancel'), supplier_articles_path(@supplier) diff --git a/app/views/articles/index.html.haml b/app/views/articles/index.html.haml index fbb549fbe..ff1dc9038 100644 --- a/app/views/articles/index.html.haml +++ b/app/views/articles/index.html.haml @@ -16,29 +16,31 @@ = text_field_tag :query, params[:query], class: 'input-medium search-query', placeholder: t('.search_placeholder') - - if @supplier.shared_supplier + - unless @supplier.supplier_remote_source.blank? .btn-group - if @supplier.shared_sync_method == 'import' = link_to t('.ext_db.import'), "#import", 'data-toggle-this' => '#import', class: 'btn btn-primary' = link_to t('.ext_db.sync'), sync_supplier_articles_path(@supplier), method: :post, class: 'btn btn-success' .btn-group - = link_to t('.new'), new_supplier_article_path(@supplier), remote: true, class: "btn #{'btn-primary' unless @supplier.shared_supplier}" + = link_to t('.migrate_units') + '...', prepare_units_migration_supplier_articles_path(@supplier), class: 'btn btn-success' if @supplier.unit_migration_completed.nil? + .btn-group + = link_to t('.new'), new_supplier_article_path(@supplier), remote: true, class: "btn #{'btn-primary' if @supplier.supplier_remote_source.nil?}" = link_to t('.edit_all'), edit_all_supplier_articles_path(@supplier), class: 'btn' = link_to t('.upload'), upload_supplier_articles_path(@supplier), class: 'btn' = link_to t('.download'), supplier_articles_path(@supplier, format: :csv), class: 'btn' - if current_user.role_orders? = link_to t('.new_order'), new_order_path(supplier_id: @supplier), class: 'btn' -- unless @supplier.shared_supplier.nil? +- unless @supplier.supplier_remote_source.blank? #import.well.well-small(style="display:none;") - = form_tag shared_supplier_articles_path(@supplier), method: :get, remote: true, class: 'form-search', + = form_tag supplier_remote_articles_path(@supplier), method: :get, remote: true, class: 'form-search', 'data-submit-onchange' => true do %h3{style: 'display: inline; vertical-align: middle; margin-right: 1em;'}= t('.import.title') + ' ' - = text_field_tag "name_cont_all_joined", "", class: 'input-medium search-query', + = text_field_tag "name", "", class: 'input-medium search-query', placeholder: t('.import.placeholder') %label.checkbox - = check_box_tag "q[origin_eq]", "REG", false + = check_box_tag "origin", "REG", false = t '.import.restrict_region' .pull-right{style: 'line-height: 40px'} = label_tag :article_category_id, t('.import.category') @@ -64,11 +66,3 @@ $('#import #article_category_id').val(''); } }); - // propagate category select to article import - // XXX quite a url hack - $(document).on('touchclick', '#import .actions a[href]', function() { - var category_id = $('#import #article_category_id').children(':selected').val(); - var url = $(this).attr('href'); - url = url.replace(/(&article_category_id=[0-9]*)?$/, '&article_category_id='+category_id); - $(this).attr('href', url); - }); diff --git a/app/views/articles/migrate_units.html.haml b/app/views/articles/migrate_units.html.haml new file mode 100644 index 000000000..f146e7657 --- /dev/null +++ b/app/views/articles/migrate_units.html.haml @@ -0,0 +1,74 @@ +- title t('.title', supplier: @supplier.name) +%span= simple_format(t('.explanation')) +- content_for :javascript do + :javascript + const units = #{raw(@all_units.to_json)}; +- content_for :javascript do + = simple_fields_for "samples[TEMPLATEREPLACEMARKER]" do |form| + :javascript + const ratioTemplateHtml = "#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: form, article_unit_ratio_counter: -1}))}"; + :javascript + $(document).ready(() => new MigrateUnitsForm(ratioTemplateHtml, $('#migrate-units'), units)); +- price_markup = FoodsoftConfig[:price_markup].to_f += render partial: 'shared/js_templates/unit_conversion_popover_template' + += form_with url: complete_units_migration_supplier_articles_path do |f| + %table.table#migrate-units + %thead + %tr + %th= t('.column_headers.apply') + %th= t('.column_headers.original_plaintext_unit') + %th= t('.column_headers.affected_articles') + %th= heading_helper ArticleVersion, :supplier_order_unit + %th= t('.column_headers.contains') + %th= heading_helper ArticleVersion, :group_order_granularity + %tbody + - @samples.each_with_index do |sample, index| + %tr{:id => "sample_row_#{index}"} + = simple_fields_for "samples[#{index}]", sample do |form| + %td + = yield form # allow to add hidden fields to form + = form.input :apply_migration, as: :boolean, label: false, input_html: { value: true, checked: 'checked' } + %td + - sample[:articles].each do |article| + = hidden_field_tag "samples[#{index}][article_ids][]", article.id + = "\"#{sample[:unit]}\"" + %td + %span.articles-list + %span.expander{role: :button} + %i.icon-chevron-sign-right + %span.collapser.d-none{role: :button} + %i.icon-chevron-sign-down + %span + = sample[:articles].length + %ul.list.d-none + - sample[:articles].each do |article| + %li + - if article.availability + = article.name + - else + %s=article.name + + %td + = form.input :supplier_order_unit, as: :select, collection: [], label: false, include_blank: t('.custom_unit'), input_html: {class: 'input-medium', 'data-initial-value': sample[:conversion_result][:supplier_order_unit]} + %td + .d-flex.gap-1 + = field_with_preset_value_and_errors(form: form, + field: :first_ratio_quantity, + value: sample[:conversion_result][:first_ratio]&.dig(:quantity), + errors: sample[:errors]&.messages&.dig(:"latest_article_version.article_unit_ratios.quantity"), + input_html: { type: :number, class: 'input-mini', required: true }) + %span + = '×'.html_safe + = form.input :first_ratio_unit, as: :select, include_blank: true, collection: [], required: false, label: false, input_html: {class: 'input-medium', 'data-initial-value': sample[:conversion_result][:first_ratio]&.dig(:unit)} + %td + .d-flex.gap-1 + = field_with_preset_value_and_errors(form: form, + field: :group_order_granularity, + value: sample[:conversion_result][:group_order_granularity], + errors: sample[:errors]&.messages&.dig(:"latest_article_version.group_order_granularity"), + input_html: { type: :number, class: 'input-mini', required: true, title: "steps in which ordergroups can order this article" }) + %span + = '×'.html_safe + = form.input :group_order_unit, as: :select, collection: [], input_html: {'data-initial-value': sample[:conversion_result][:group_order_unit], class: 'input-medium'}, label: false, include_blank: false + = f.submit t('.run_migration'), class: 'btn btn-primary' diff --git a/app/views/articles/new.js.haml b/app/views/articles/new.js.haml index 504f55277..1424b96fb 100644 --- a/app/views/articles/new.js.haml +++ b/app/views/articles/new.js.haml @@ -1,2 +1,2 @@ -$('#modalContainer').html('#{j(render("form"))}'); +$('#modalContainer').addClass('modal-xl').html('#{j(render("form"))}'); $('#modalContainer').modal(); diff --git a/app/views/articles/prepare_units_migration.haml b/app/views/articles/prepare_units_migration.haml new file mode 100644 index 000000000..5e22ee7b4 --- /dev/null +++ b/app/views/articles/prepare_units_migration.haml @@ -0,0 +1,8 @@ +- title t('.title', supplier: @supplier.name) +%p.mb-1 + =simple_format(t('.explanation')) += link_to t('.download'), supplier_articles_path(@supplier, format: :csv), class: 'btn' +%br/ +%br/ +%p.mt-1 + = link_to t('.migrate_units') + '...', migrate_units_supplier_articles_path(@supplier), class: 'btn btn-success' if @supplier.unit_migration_completed.nil? diff --git a/app/views/articles/shared.js.haml b/app/views/articles/shared.js.haml deleted file mode 100644 index 23816d7e1..000000000 --- a/app/views/articles/shared.js.haml +++ /dev/null @@ -1 +0,0 @@ -$('#search_results').html('#{escape_javascript(render("import_search_results"))}'); diff --git a/app/views/articles/update.js.haml b/app/views/articles/update.js.haml index e007307e8..71a2ed0b7 100644 --- a/app/views/articles/update.js.haml +++ b/app/views/articles/update.js.haml @@ -1,2 +1,2 @@ $('#article_#{@article.id}').replaceWith('#{escape_javascript(render(@article))}'); -$('#modalContainer').modal('hide'); +$('#modalContainer').removeClass('modal-xl').modal('hide'); diff --git a/app/views/articles/upload.html.haml b/app/views/articles/upload.html.haml index 8f91d790c..b01fe0d2e 100644 --- a/app/views/articles/upload.html.haml +++ b/app/views/articles/upload.html.haml @@ -5,66 +5,87 @@ %table.table.table-bordered %thead %tr - %th= t '.field.status' + %th= Article.human_attribute_name(:availability_short) %th= Article.human_attribute_name(:order_number) %th= Article.human_attribute_name(:name) - %th= Article.human_attribute_name(:note) - %th= Article.human_attribute_name(:manufacturer) - %th= Article.human_attribute_name(:origin) - %th= Article.human_attribute_name(:unit) + %th= Article.human_attribute_name(:supplier_order_unit) + %th= Article.human_attribute_name(:custom_unit) + %th= Article.human_attribute_name(:ratios_to_supplier_order_unit) + %th= Article.human_attribute_name(:minimum_order_quantity) + %th= Article.human_attribute_name(:billing_unit) + %th= Article.human_attribute_name(:group_order_granularity) + %th= Article.human_attribute_name(:group_order_unit) %th= Article.human_attribute_name(:price) + %th= Article.human_attribute_name(:price_unit) %th= Article.human_attribute_name(:tax) %th= Article.human_attribute_name(:deposit) - %th= Article.human_attribute_name(:unit_quantity) - %th.muted= t '.fields.reserved' - %th.muted= t '.fields.reserved' + %th= Article.human_attribute_name(:note) %th= Article.human_attribute_name(:article_category) + %th= Article.human_attribute_name(:origin) + %th= Article.human_attribute_name(:manufacturer) %tbody + - kgm = ArticleUnitsLib.get_translated_name_for_code('KGM') + - xjy = ArticleUnitsLib.get_translated_name_for_code('XJY') + - ltr = ArticleUnitsLib.get_translated_name_for_code('LTR') + - xbd = ArticleUnitsLib.get_translated_name_for_code('XBD') + - xbo = ArticleUnitsLib.get_translated_name_for_code('XBO') %tr %td %td 1234A %td= t '.sample.walnuts' + %td= kgm %td - %td= t '.sample.supplier_1' - %td CA - %td 500 gr - %td 8.90 + %td + %td + %td= kgm + %td 0.5 + %td= kgm + %td 17.80 + %td= kgm %td= FoodsoftConfig[:tax_default] || 6 %td 0 - %td 6 - %td %td %td= t '.sample.nuts' + %td CA + %td= t '.sample.supplier_1' %tr %td x %td 4321Z %td= t '.sample.tomato_juice' - %td= t '.sample.organic' - %td= t '.sample.supplier_2' - %td IN - %td 1.5 l + %td= xjy + %td + %td= '1.5 ' + ltr + %td 4 + %td= ltr + %td 1 + %td= xjy %td 4.35 + %td= ltr %td= FoodsoftConfig[:tax_default] || 6 %td 0 - %td 1 - %td - %td + %td= t '.sample.organic' %td= t '.sample.juices' + %td IN + %td= t '.sample.supplier_2' %tr %td %td 4322Q %td= t '.sample.tomato_juice' - %td= t '.sample.organic' - %td= t '.sample.supplier_3' - %td TR - %td 1.2 l + %td= xbd + %td + %td= '6 ' + xbo + ', 1 ' + ltr + %td + %td= xbd + %td 1 + %td= xbo %td 4.02 + %td= xbo %td= FoodsoftConfig[:tax_default] || 6 %td 0 - %td 2 - %td - %td + %td= t '.sample.organic' %td= t '.sample.juices' + %td TR + %td= t '.sample.supplier_3' %p= t '.text_2' diff --git a/app/views/deliveries/_stock_article_for_adding.html.haml b/app/views/deliveries/_stock_article_for_adding.html.haml index 5463bc8fe..83356365d 100644 --- a/app/views/deliveries/_stock_article_for_adding.html.haml +++ b/app/views/deliveries/_stock_article_for_adding.html.haml @@ -4,8 +4,8 @@ %tr{:id => "stock_article_#{article.id}", :class => css_class} %td= article.name - %td{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_price_info', :locals => {:article => article})}"}}= number_to_currency article.price - %td= article.unit + %td{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_version_info', :locals => {:article => article})}"}}= number_to_currency article.price + %td= format_supplier_order_unit(article) %td= article.article_category.name %td = link_to t('.action_edit'), edit_stock_article_path(article), remote: true, class: 'btn btn-mini' diff --git a/app/views/deliveries/_stock_change_fields.html.haml b/app/views/deliveries/_stock_change_fields.html.haml index 40ec59228..65418accb 100644 --- a/app/views/deliveries/_stock_change_fields.html.haml +++ b/app/views/deliveries/_stock_change_fields.html.haml @@ -4,7 +4,7 @@ %td %span.stock_article_name= stock_change.stock_article.name = f.association :stock_article, :as => :hidden - %td.price{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_price_info', :locals => {:article => stock_article})}"}}= number_to_currency stock_article.price - %td.unit= stock_change.stock_article.unit + %td.price{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_version_info', :locals => {:article => stock_article})}"}}= number_to_currency stock_article.price + %td.unit= format_supplier_order_unit(stock_change.stock_article) %td= f.input :quantity, :wrapper => :intable, :input_html => {:class => 'stock-change-quantity', :autocomplete => :off} %td= stock_change_remove_link f diff --git a/app/views/deliveries/add_stock_change.js.erb b/app/views/deliveries/add_stock_change.js.erb index 2d01bc68d..611f7c4d5 100644 --- a/app/views/deliveries/add_stock_change.js.erb +++ b/app/views/deliveries/add_stock_change.js.erb @@ -2,21 +2,21 @@ if(!is_article_available_for_delivery(<%= @stock_change.stock_article.id %>)) { return false; } - + $('#stock_changes tr').removeClass('success'); - - var quantity = w.prompt('<%= j(t('.how_many_units', :unit => @stock_change.stock_article.unit, :name => @stock_change.stock_article.name)) %>'); + + var quantity = w.prompt('<%= j(t('.how_many_units', :unit => format_supplier_order_unit(@stock_change.stock_article), :name => @stock_change.stock_article.name)) %>'); if(null === quantity) { return false; } - + var stock_change = $( '<%= j(render(:partial => 'stock_change', :locals => {:stock_change => @stock_change})) %>' ).addClass('success'); $('input.stock-change-quantity', stock_change).val(quantity); - + $('#stock_changes').append(stock_change); mark_article_for_delivery(<%= @stock_change.stock_article.id %>); updateSort('#stock_changes'); - + })(window); diff --git a/app/views/deliveries/show.html.haml b/app/views/deliveries/show.html.haml index 83f6f15bc..96c231b68 100644 --- a/app/views/deliveries/show.html.haml +++ b/app/views/deliveries/show.html.haml @@ -31,7 +31,7 @@ - total_gross += quantity * stock_change.stock_article.gross_price %tr %td= stock_change.stock_article.name - %td= stock_change.stock_article.unit + %td= format_supplier_order_unit_with_ratios(stock_change.stock_article) %td.numeric= quantity %td.numeric= number_to_currency stock_change.stock_article.price %td.numeric= number_to_currency sum diff --git a/app/views/finance/balancing/_group_order_articles.html.haml b/app/views/finance/balancing/_group_order_articles.html.haml index 896cea3c4..41f216405 100644 --- a/app/views/finance/balancing/_group_order_articles.html.haml +++ b/app/views/finance/balancing/_group_order_articles.html.haml @@ -20,13 +20,14 @@ %td{:style=>"width:50%"} = group_order_article.group_order.ordergroup_name %td.center= group_order_article_edit_result(group_order_article) - %td.numeric= number_to_currency(group_order_article.order_article.price.fc_price * group_order_article.result) + %td.numeric= number_to_currency(group_order_article.order_article.article_version.fc_group_order_price * group_order_article.result) %td.actions{:style=>"width:1em"} - unless order_article.order.closed? = link_to t('ui.delete'), group_order_article_path(group_order_article), method: :delete, remote: true, class: 'btn btn-mini btn-danger' %td - - totals[:result] += group_order_article.result + - article_version = order_article.article_version + - totals[:result] += article_version.convert_quantity(group_order_article.result, article_version.group_order_unit, article_version.billing_unit) %tfoot %tr %td diff --git a/app/views/finance/balancing/_order_article.html.haml b/app/views/finance/balancing/_order_article.html.haml index 47db3e31a..f7942a7a3 100644 --- a/app/views/finance/balancing/_order_article.html.haml +++ b/app/views/finance/balancing/_order_article.html.haml @@ -1,24 +1,24 @@ %td.closed.name - = link_to order_article.article.name, '#', 'data-toggle-this' => "#group_order_articles_#{order_article.id}" -%td= order_article.article.order_number -%td{title: units_history_line(order_article, :plain => true)} - = order_article.units - = pkg_helper order_article.article_price - - if s=order_article.ordered_quantities_different_from_group_orders? + = link_to order_article.article_version.name, '#', 'data-toggle-this' => "#group_order_articles_#{order_article.id}" +%td= order_article.article_version.order_number +%td{title: units_history_line(order_article, plain: true, unit: order_article.article_version.billing_unit)} + = order_article.article_version.convert_quantity(order_article.units, order_article.article_version.supplier_order_unit, order_article.article_version.billing_unit).round(3).to_s + = pkg_helper(order_article.article_version, unit: order_article.article_version.billing_unit) + - if s=ordered_quantities_different_from_group_orders?(order_article) %span{:style => "color:red;font-weight: bold"}= s -%td #{order_article.article.unit} +%td #{format_billing_unit_with_ratios(order_article.article_version)} %td - = number_to_currency(order_article.price.price, :unit => "") + = number_to_currency(order_article.article_version.price, :unit => "") :plain / = number_to_currency(order_article.total_price, :unit => "") %td - = number_to_currency(order_article.price.gross_price, :unit => "") + = number_to_currency(order_article.article_version.gross_price, :unit => "") :plain / = number_to_currency(order_article.total_gross_price, :unit => "") -%td= number_to_percentage(order_article.price.tax) unless order_article.price.tax.zero? -%td= number_to_currency(order_article.price.deposit, :unit => "") unless order_article.price.deposit.zero? +%td= number_to_percentage(order_article.article_version.tax) unless order_article.article_version.tax.zero? +%td= number_to_currency(order_article.article_version.deposit, :unit => "") unless order_article.article_version.deposit.zero? %td = link_to t('ui.edit'), edit_order_order_article_path(order_article.order, order_article), remote: true, class: 'btn btn-mini' unless order_article.order.closed? diff --git a/app/views/finance/balancing/new.html.haml b/app/views/finance/balancing/new.html.haml index 7e143e082..5349ddb1c 100644 --- a/app/views/finance/balancing/new.html.haml +++ b/app/views/finance/balancing/new.html.haml @@ -1,3 +1,4 @@ += render partial: 'shared/js_templates/unit_conversion_popover_template', locals: {set_units_data: true} - content_for :javascript do :javascript $(function() { @@ -11,7 +12,7 @@ contentType: 'application/json; charset=UTF-8' }); }); - + $(document).on('OrderArticle#create', function(e) { $.ajax({ url: '#{new_on_order_article_create_finance_order_path(@order)}', @@ -20,6 +21,12 @@ contentType: 'application/json; charset=UTF-8' }); }); + + $('*[name="group_order_article[result]"]').each((_, field) => $(field).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false + })); }); = render 'shared/articles_by/common', order: @order @@ -40,7 +47,7 @@ - unless @order.note.blank? = simple_format @order.note - else - %p= t('.comment_on_transaction') + %p= t('.comment_on_transaction') = link_to t('.edit_note'), edit_note_finance_order_path(@order), remote: true .well.well-small diff --git a/app/views/finance/balancing/new.js.haml b/app/views/finance/balancing/new.js.haml index 0bd073fd8..224e225fd 100644 --- a/app/views/finance/balancing/new.js.haml +++ b/app/views/finance/balancing/new.js.haml @@ -1 +1,6 @@ $('#results').html('#{j(render(balancing_view_partial, order: @order))}'); +$('*[name="group_order_article[result]"]').each((_, field) => $(field).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false +})); diff --git a/app/views/finance/balancing/new_on_order_article_create.js.erb b/app/views/finance/balancing/new_on_order_article_create.js.erb index 5e55a80a0..9a88243c3 100644 --- a/app/views/finance/balancing/new_on_order_article_create.js.erb +++ b/app/views/finance/balancing/new_on_order_article_create.js.erb @@ -2,15 +2,21 @@ // See publish/subscribe design pattern in /doc. (function(w) { $('#order_article_<%= @order_article.id %>').remove(); // just to be sure: remove table row which is added below - + $('#ordered-articles tr').removeClass('success'); - + var order_article_entry = $( '<%= j render('finance/balancing/order_article_result', order_article: @order_article) %>' ).addClass('success'); - + $('#result_table').prepend(order_article_entry); - + $('#summaryChangedWarning').show(); + + $('*[name="group_order_article[result]"]').each((_, field) => $(field).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false + })); })(window); diff --git a/app/views/finance/balancing/new_on_order_article_update.js.erb b/app/views/finance/balancing/new_on_order_article_update.js.erb index a3fe6c27d..71a4c3147 100644 --- a/app/views/finance/balancing/new_on_order_article_update.js.erb +++ b/app/views/finance/balancing/new_on_order_article_update.js.erb @@ -4,11 +4,17 @@ $('#order_article_<%= @order_article.id %>').html( '<%= j render('finance/balancing/order_article', order_article: @order_article) %>' ); - + $('#group_order_articles_<%= @order_article.id %>').html( '<%= j render('finance/balancing/group_order_articles', order_article: @order_article) %>' ); - + $('#summaryChangedWarning').show(); + + $('*[name="group_order_article[result]"]').each((_, field) => $(field).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false + })); })(window); diff --git a/app/views/group_order_articles/_form.html.haml b/app/views/group_order_articles/_form.html.haml index e0921d4e6..7a7ade623 100644 --- a/app/views/group_order_articles/_form.html.haml +++ b/app/views/group_order_articles/_form.html.haml @@ -2,10 +2,10 @@ = form.hidden_field :order_article_id .modal-header = close_button :modal - %h3= t('.amount_change_for', article: @order_article.article.name) + %h3= t('.amount_change_for', article: @order_article.article_version.name) .modal-body = form.input :ordergroup_id, as: :select, collection: Ordergroup.undeleted.map { |g| [g.name, g.id] } - = form.input :result, hint: I18n.t('group_order_articles.form.result_hint', unit: @order_article.article.unit) # Why do we need the full prefix? + = form.input :result, hint: I18n.t('group_order_articles.form.result_hint', unit: format_group_order_unit_with_ratios(@order_article.article_version)) # Why do we need the full prefix? .modal-footer = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'} = form.submit t('ui.save'), class: 'btn btn-primary' diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml index 9061bdf85..7bf77a657 100644 --- a/app/views/group_orders/_form.html.haml +++ b/app/views/group_orders/_form.html.haml @@ -1,12 +1,14 @@ += render partial: 'shared/js_templates/unit_conversion_popover_template', locals: {set_units_data: true} - content_for :javascript do - group_balance = FoodsoftConfig[:charge_members_manually] ? @ordering_data[:account_balance] : @ordering_data[:available_funds] :javascript + new GroupOrderForm($('.group_order_form'), { + units: unitsData, + toleranceIsCostly: #{(FoodsoftConfig[:tolerance_is_costly] or false).to_json}, + groupBalance: #{group_balance}, + minimumBalance: #{FoodsoftConfig[:minimum_balance] or 0} + }); $(function() { - #{data_to_js(@ordering_data)} - setGroupBalance(#{group_balance}); - setMinimumBalance(#{FoodsoftConfig[:minimum_balance] or 0}); - setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]}); - setStockit(#{@order.stockit?}); // create List for search-feature (using list.js, http://listjs.com) var listjsResetPlugin = ['reset', {highlightClass: 'btn-primary'}]; var listjsDelayPlugin = ['delay', {delayedSearchTime: 500}]; @@ -21,7 +23,6 @@ }); - title t('.title'), false - .row-fluid .well.pull-left = close_button :alert @@ -64,7 +65,7 @@ %button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')} %i.icon.icon-remove -= form_for @group_order do |f| += form_for @group_order, html: {class: 'group_order_form'} do |f| = f.hidden_field :lock_version = f.hidden_field :order_id = f.hidden_field :updated_by_user_id @@ -80,12 +81,12 @@ %th{style: "width:4.5em;"}= heading_helper Article, :unit - unless @order.stockit? %th{style: "width:70px;"}= heading_helper OrderArticle, :missing_units, short: true - %th#col_required= heading_helper GroupOrderArticle, :quantity - %th#col_tolerance= heading_helper GroupOrderArticle, :tolerance + %th#col_required{colspan: 2}= heading_helper GroupOrderArticle, :quantity + %th#col_tolerance{colspan: 2}= heading_helper GroupOrderArticle, :tolerance - else %th(style="width:20px")= heading_helper StockArticle, :available - %th#col_required= heading_helper GroupOrderArticle, :quantity - %th{style: "width:15px;"}= heading_helper GroupOrderArticle, :total_price + %th#col_required{colspan: 2}= heading_helper GroupOrderArticle, :quantity + %th{style: "width:15px;text-align:right;"}= heading_helper GroupOrderArticle, :total_price %tbody.list - @order.articles_grouped_by_category.each do |category, order_articles| %tr.list-heading.article-category @@ -94,49 +95,62 @@ %i.icon-tag %td{colspan: "9"} - order_articles.each do |order_article| - %tr{class: "#{cycle('even', 'odd', name: 'articles')} order-article #{get_missing_units_css_class(@ordering_data[:order_articles][order_article.id][:missing_units])}", valign: "top"} - %td.name= order_article.article.name + %tr{class: "#{cycle('even', 'odd', name: 'articles')} order-article #{get_missing_units_css_class(@ordering_data[:order_articles][order_article.id][:missing_units], order_article.article_version)}", valign: "top"} + %td.name= order_article.article_version.name - if @order.stockit? - %td= truncate order_article.article.supplier.name, length: 15 - %td= h order_article.article.origin + %td= truncate order_article.article_version.article.supplier.name, length: 15 + %td= h order_article.article_version.origin %td= number_to_currency(@ordering_data[:order_articles][order_article.id][:price]) - %td= order_article.article.unit + %td.group-order-unit= format_group_order_unit_with_ratios(order_article.article_version) %td - if @order.stockit? = @ordering_data[:order_articles][order_article.id][:quantity_available] - else - %span{id: "missing_units_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:missing_units] + %span.missing-units= @ordering_data[:order_articles][order_article.id][:missing_units] - %td.quantity - %input{id: "q_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:quantity], 'data-min' => (@ordering_data[:order_articles][order_article.id][:quantity] if @order.boxfill?), 'data-max' => (@ordering_data[:order_articles][order_article.id][:quantity]+@ordering_data[:order_articles][order_article.id][:missing_units] if @order.boxfill?)}/ - %span.used{id: "q_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_quantity] + - quantity_data = ratio_quantity_data(order_article, order_article.article_version.group_order_unit) + - quantity_data['ratio-group-order-unit-supplier-unit'] = @ordering_data[:order_articles][order_article.id][:ratio_group_order_unit_supplier_unit] + - quantity_data['others_quantity'] = @ordering_data[:order_articles][order_article.id][:others_quantity] + - quantity_data['others_tolerance'] = @ordering_data[:order_articles][order_article.id][:others_tolerance] + - quantity_data['used_quantity'] = @ordering_data[:order_articles][order_article.id][:used_quantity] + - quantity_data['price'] = @ordering_data[:order_articles][order_article.id][:price] + - quantity_data['minimum_order_quantity'] = @ordering_data[:order_articles][order_article.id][:minimum_order_quantity] unless @ordering_data[:order_articles][order_article.id][:minimum_order_quantity].nil? + - quantity_data['e2e-order-article-id'] = order_article.id + %td.used-unused + %span.used= number_with_precision(@ordering_data[:order_articles][order_article.id][:used_quantity], precision: 3, strip_insignificant_zeros: true) + - %span.unused{id: "q_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity] - .btn-group - %a.btn.btn-ordering{'data-increase_quantity' => order_article.id} - %i.icon-plus - %a.btn.btn-ordering{'data-decrease_quantity' => order_article.id} + %span.unused= number_with_precision(@ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity], precision: 3, strip_insignificant_zeros: true) + %td.quantity.group-order-input{class: ('stock-order' if @order.stockit?)} + .btn-group.numeric-step + %a.btn.btn-ordering.decrease %i.icon-minus + %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', style: ('display:none' if @order.stockit?), min: 0, max: (@ordering_data[:order_articles][order_article.id][:quantity_available] if @order.stockit?), step: order_article.article_version.group_order_granularity} + %span.numeric-step-error + = t('errors.step_error', granularity: order_article.article_version.group_order_granularity, min: 0) - %td.tolerance{style: ('display:none' if @order.stockit?)} - %input{id: "t_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][tolerance]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:tolerance], 'data-min' => (@ordering_data[:order_articles][order_article.id][:tolerance] if @order.boxfill?)}/ - - if (@ordering_data[:order_articles][order_article.id][:unit] > 1) - %span.used{id: "t_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_tolerance] + %td.used-unused-tolerance{style: ('display:none' if @order.stockit?)} + - if (order_article.article_version.uses_tolerance?) + %span.used= number_with_precision(@ordering_data[:order_articles][order_article.id][:used_tolerance], precision: 3, strip_insignificant_zeros: true) + - %span.unused{id: "t_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] - @ordering_data[:order_articles][order_article.id][:used_tolerance] + %span.unused= number_with_precision(@ordering_data[:order_articles][order_article.id][:tolerance] - @ordering_data[:order_articles][order_article.id][:used_tolerance], precision: 3, strip_insignificant_zeros: true) + %td.tolerance.group-order-input{style: ('display:none' if @order.stockit?)} + - if (order_article.article_version.uses_tolerance?) .btn-group - %a.btn.btn-ordering{'data-increase_tolerance' => order_article.id} - %i.icon-plus - %a.btn.btn-ordering{'data-decrease_tolerance' => order_article.id} + %a.btn.btn-ordering.decrease %i.icon-minus + %a.btn.btn-ordering.increase + %i.icon-plus + %input.goa-tolerance{type: "number", name: "group_order[group_order_articles_attributes][#{order_article.id}][tolerance]", data: quantity_data, value: @ordering_data[:order_articles][order_article.id][:tolerance], autocomplete: 'off', class: 'input-mini numeric', min: 0, step: order_article.article_version.group_order_granularity, max: [@ordering_data[:order_articles][order_article.id][:ratio_group_order_unit_supplier_unit], @ordering_data[:order_articles][order_article.id][:minimum_order_quantity].presence || 0].max} %td{id: "td_price_#{order_article.id}", style: "text-align:right; padding-right:10px; width:4em"} - %span{id: "price_#{order_article.id}_display"}= number_to_currency(@ordering_data[:order_articles][order_article.id][:total_price]) + %span{id: "price_#{order_article.id}_display", data: {price: @ordering_data[:order_articles][order_article.id][:total_price]}}= number_to_currency(@ordering_data[:order_articles][order_article.id][:total_price]) .article-info - .article-name= order_article.article.name + .article-name= order_article.article_version.name .pull-right = t('.units_full') + ':' - %span{id: "units_#{order_article.id}"}= order_article.units_to_order + %span{id: "units_#{order_article.id}"}= order_article.article_version.convert_quantity(order_article.units_to_order, order_article.article_version.supplier_order_unit, order_article.article_version.group_order_unit) %br/ = t('.units_total') + ':' %span{id: "q_total_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] + @ordering_data[:order_articles][order_article.id][:others_quantity] @@ -145,11 +159,18 @@ %span{id: "t_total_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] + @ordering_data[:order_articles][order_article.id][:others_tolerance] %br/ .pull-left - #{heading_helper Article, :manufacturer}: #{order_article.article.manufacturer} + #{heading_helper Article, :manufacturer}: #{order_article.article_version.manufacturer} %br/ - #{heading_helper Article, :units}: #{@order.stockit? ? order_article.article.quantity_available : @ordering_data[:order_articles][order_article.id][:unit]} * #{h order_article.article.unit} + #{heading_helper Article, :units}: + - if @order.stockit? + #{order_article.article_version.article.quantity_available} + - elsif order_article.article_version.uses_tolerance? + #{format_supplier_order_unit_with_ratios(order_article.article_version)} + - else + #{format_group_order_unit_with_ratios(order_article.article_version)} + %br/ - #{heading_helper Article, :note}: #{order_article.article.note} + #{heading_helper Article, :note}: #{order_article.article_version.note} %br/ #order-footer #info-box @@ -174,8 +195,8 @@ %strong %span#new_balance= number_to_currency(old_balance - @group_order.price) %span#order-button - = submit_tag( t('.action_save'), id: 'submit_button', class: 'btn btn-primary' ) + = submit_tag( t('.action_save'), id: 'submit_button', class: 'btn btn-primary', disabled: 'disabled' ) = link_to t('.account_statement'), my_ordergroup_path, class: 'btn btn-secondary btn-small hidden', id: 'account-statement-button' - #{link_to t('ui.or_cancel'), group_orders_path} + #{link_to t('ui.or_cancel'), group_orders_path} %input#total_balance{name: "total_balance", type: "hidden", value: @ordergroup.account_balance - @group_order.price}/ %input{name: "version", type: "hidden", value: @version}/ diff --git a/app/views/group_orders/show.html.haml b/app/views/group_orders/show.html.haml index 8c9678d7c..149a08dcb 100644 --- a/app/views/group_orders/show.html.haml +++ b/app/views/group_orders/show.html.haml @@ -72,19 +72,19 @@ - r = get_order_results(oa, @group_order.id) %tr{class: cycle('even', 'odd', name: 'articles') + " " + order_article_class_name(r[:quantity], r[:tolerance], r[:result])} %td{style: "width:40%"} - = oa.article.name - - unless oa.article.note.blank? + = oa.article_version.name + - unless oa.article_version.note.blank? = image_tag("lamp_grey.png", {alt: t('.articles.show_note'), size: "15x16", border: "0", onmouseover: "$('#note_#{oa.id}').show();", onmouseout: "$('#note_#{oa.id}').hide();"}) - %td= "#{oa.price.unit_quantity} x #{oa.article.unit}" - %td= number_to_currency(oa.price.fc_price) + %td= format_group_order_unit_with_ratios(oa.article_version) + %td= number_to_currency(oa.article_version.fc_group_order_price) %td = r[:quantity] - = "+ #{r[:tolerance]}" if oa.price.unit_quantity > 1 + = "+ #{r[:tolerance]}" if oa.article_version.unit_quantity > 1 %td= r[:result] > 0 ? r[:result] : "0" %td= number_to_currency(r[:sub_total]) - - unless oa.article.note.blank? + - unless oa.article_version.note.blank? %tr{id: "note_#{oa.id}", class: "note even", style: "display:none"} - %td{colspan: "6"}=h oa.article.note + %td{colspan: "6"}=h oa.article_version.note %tr{class: cycle('even', 'odd', name: 'articles')} %th{colspan: "5"}= heading_helper GroupOrder, :price %th= number_to_currency(@group_order.price) diff --git a/app/views/mailer/order_received.text.haml b/app/views/mailer/order_received.text.haml index 79f01c5d6..8ff80c25f 100644 --- a/app/views/mailer/order_received.text.haml +++ b/app/views/mailer/order_received.text.haml @@ -3,11 +3,11 @@ - unless @abundant_articles.empty? = raw "===\n" + t('.abundant_articles') + ":" - @abundant_articles.each do |order_article| - - article = order_article.article + - article = order_article.article_version = raw t('.article_details', name: article.name, ordered: order_article.units_to_order, received: order_article.units_received, unit: article.unit) - unless @scarce_articles.empty? = raw "===\n" + t('.scarce_articles') + ":" - @scarce_articles.each do |order_article| - - article = order_article.article + - article = order_article.article_version = raw t('.article_details', name: article.name, ordered: order_article.units_to_order, received: order_article.units_received, unit: article.unit) diff --git a/app/views/mailer/order_result.text.haml b/app/views/mailer/order_result.text.haml index 077207d7e..3900fa867 100644 --- a/app/views/mailer/order_result.text.haml +++ b/app/views/mailer/order_result.text.haml @@ -3,6 +3,6 @@ = raw t '.text1', pickup: I18n.l(@order.pickup) = raw t '.text2' - for group_order_article in @group_order.group_order_articles.ordered.includes(:order_article) - - article = group_order_article.order_article.article + - article = group_order_article.order_article.article_version \- #{article.name}: #{group_order_article.result} x #{article.unit} = #{group_order_article.result * article.fc_price} = raw t '.text3', sum: @group_order.price, order_url: group_order_url(@group_order), foodcoop: FoodsoftConfig[:name] diff --git a/app/views/order_articles/_edit.html.haml b/app/views/order_articles/_edit.html.haml index 047e1391d..41e09e7f3 100644 --- a/app/views/order_articles/_edit.html.haml +++ b/app/views/order_articles/_edit.html.haml @@ -2,28 +2,33 @@ .modal-header = close_button :modal %h3= t '.title' - .modal-body + .modal-body.article-form - if params[:without_units] = hidden_field_tag :without_units, true - else .fold-line - = form.input :units_to_order, hint: '', input_html: {class: 'input-nano'} + = form.input :units_to_order, hint: '', input_html: {class: 'input-mini', step: 0.001} -#= form.input :units_billed, label: 'invoice', input_html: {class: 'input-nano'} - = form.input :units_received, input_html: {class: 'input-nano'}, + = form.input :units_received, input_html: {class: 'input-mini', step: 0.001}, label: t('activerecord.attributes.order_article.units_received_short') %p.help-block= t 'simple_form.hints.order_article.units_to_order' .foo{style: 'clear:both'} - = simple_fields_for :article, @order_article.article do |f| + = simple_fields_for @order_article.article_version do |f| = f.input :name - - if @order_article.article.is_a?(StockArticle) + - if @order_article.article_version.is_a?(StockArticle) %div.alert= t '.stock_alert' - else - = simple_fields_for :article_price, @order_article.article_price do |fprice| - = render partial: 'shared/article_fields_units', locals: {f_unit: f, f_uq: fprice} - = render partial: 'shared/article_fields_price', locals: {f: fprice} + = simple_fields_for :article_version, @order_article.article_version do |fprice| + :javascript + const articleUnitRatioTemplate$ = $($.parseHTML("#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: fprice, article_unit_ratio_counter: -1}))}")); + const units = #{raw(@all_units.to_json)}; + new ArticleForm(articleUnitRatioTemplate$, $('.article-form').parents('form'), units, #{FoodsoftConfig[:price_markup].to_f}); + = render partial: 'shared/js_templates/unit_conversion_popover_template' + = render partial: 'shared/article_fields_units', locals: {f: fprice, article: @order_article.article_version} + = render partial: 'shared/article_fields_price', locals: {f: fprice, article: @order_article.article_version} = form.input :update_global_price, as: :boolean = f.input :order_number diff --git a/app/views/order_articles/_new.html.haml b/app/views/order_articles/_new.html.haml index 5a87b5dfa..336abc1d5 100644 --- a/app/views/order_articles/_new.html.haml +++ b/app/views/order_articles/_new.html.haml @@ -3,7 +3,7 @@ = close_button :modal %h3= t '.title' .modal-body - = form.association :article, collection: @order.supplier_articles, label_method: lambda {|a| article_label_with_unit(a)} + = form.association :article_version, collection: @order.supplier_articles.map(&:latest_article_version), label_method: lambda {|a| article_label_with_unit(a)} .modal-footer = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'} = form.submit class: 'btn btn-primary' diff --git a/app/views/order_articles/edit.js.haml b/app/views/order_articles/edit.js.haml index 979e34cb3..e06d68ae0 100644 --- a/app/views/order_articles/edit.js.haml +++ b/app/views/order_articles/edit.js.haml @@ -1,2 +1,2 @@ -$('#modalContainer').html('#{j(render("edit"))}'); -$('#modalContainer').modal(); \ No newline at end of file +$('#modalContainer').addClass('modal-xl').html('#{j(render("edit"))}'); +$('#modalContainer').modal(); diff --git a/app/views/order_articles/new.js.haml b/app/views/order_articles/new.js.haml index 4a44300f7..3168a44de 100644 --- a/app/views/order_articles/new.js.haml +++ b/app/views/order_articles/new.js.haml @@ -1,2 +1,2 @@ $('#modalContainer').html('#{j(render("new"))}'); -$('#modalContainer').modal(); \ No newline at end of file +$('#modalContainer').modal(); diff --git a/app/views/orders/_articles.html.haml b/app/views/orders/_articles.html.haml index 1c800cc7d..95ad0516f 100644 --- a/app/views/orders/_articles.html.haml +++ b/app/views/orders/_articles.html.haml @@ -18,26 +18,26 @@ %i.icon-tag %td{:colspan => "9"} - order_articles.each do |order_article| - - net_price = order_article.price.price - - gross_price = order_article.price.gross_price - - unit_quantity = order_article.price.unit_quantity + - article = order_article.price + - net_price = article.price + - gross_price = article.gross_price - units = order_article.units - - total_net += units * unit_quantity * net_price - - total_gross += units * unit_quantity * gross_price + - total_net += units * article.price + - total_gross += units * article.gross_price %tr{:class => cycle('even', 'odd', :name => 'articles') + ' ' + order_article_class(order_article)} - %td.name=h order_article.article.name - %td= order_article.article.unit + %td.name=h order_article.article_version.name + %td= format_group_order_unit_with_ratios(order_article.article_version) %td= "#{number_to_currency(net_price)} / #{number_to_currency(gross_price)}" - if order.stockit? - %td= units + %td= = number_with_precision(units, precision: 3, strip_insignificant_zeros: true) - else - - if unit_quantity > 1 or order_article.tolerance > 0 - %td= "#{order_article.quantity} + #{order_article.tolerance}" + - if order_article.tolerance > 0 + %td= "#{number_with_precision(order_article.quantity, precision: 3, strip_insignificant_zeros: true)} + #{number_with_precision(order_article.tolerance, precision: 3, strip_insignificant_zeros: true)}" - else - %td= "#{order_article.quantity}" + %td= "#{number_with_precision(order_article.quantity, precision: 3, strip_insignificant_zeros: true)}" %td{title: units_history_line(order_article, plain: true)} - = units - = pkg_helper order_article.price + = number_with_precision(units, precision: 3, strip_insignificant_zeros: true) + = pkg_helper article %p = t '.prices_sum' = "#{number_to_currency(total_net)} / #{number_to_currency(total_gross)}" diff --git a/app/views/orders/_edit_amount.html.haml b/app/views/orders/_edit_amount.html.haml index 22e6c4a4e..ad334c020 100644 --- a/app/views/orders/_edit_amount.html.haml +++ b/app/views/orders/_edit_amount.html.haml @@ -4,25 +4,25 @@ - cssclass += " unavailable" if (order_article.units_billed||order_article.units_to_order)==0 and order_article.units_received.nil? %tr{id: "order_article_#{order_article.id}", class: cssclass, valign: "top"} - order_title = [] - - order_title.append Article.human_attribute_name(:manufacturer)+': ' + order_article.article.manufacturer unless order_article.article.manufacturer.to_s.empty? - - order_title.append Article.human_attribute_name(:note)+': ' + order_article.article.note unless order_article.article.note.to_s.empty? - %td= order_article.article.order_number - %td.name{title: order_title.join("\n")}= order_article.article.name - %td.unit= order_article.article.unit - %td.article_price - = number_to_currency order_article.article_price.price - = article_price_change_hint(order_article) + - order_title.append Article.human_attribute_name(:manufacturer)+': ' + order_article.article_version.manufacturer unless order_article.article_version.manufacturer.to_s.empty? + - order_title.append Article.human_attribute_name(:note)+': ' + order_article.article_version.note unless order_article.article_version.note.to_s.empty? + %td= order_article.article_version.order_number + %td.name{title: order_title.join("\n")}= order_article.article_version.name + %td.unit= format_group_order_unit_with_ratios(order_article.article_version) + %td.article_version + = number_to_currency order_article.article_version.group_order_price + = article_version_change_hint(order_article) %td #{order_article.quantity} + #{order_article.tolerance} %td = order_article.units_to_order - = pkg_helper order_article.article + = pkg_helper order_article.price -#%td # TODO implement invoice screen - unless order_article.units_billed.nil? = order_article.units_billed - = pkg_helper order_article.article, soft_uq: true + = pkg_helper order_article.article_version, soft_uq: true %td.units_received_cell = receive_input_field(form) - = pkg_helper order_article.article_price, icon: false, soft_uq: true + = pkg_helper order_article.article_version, icon: false, soft_uq: true, unit: order_article.article_version.billing_unit / TODO add almost invisible text_field for entering single units %td.units_delta %td diff --git a/app/views/orders/_edit_amounts.html.haml b/app/views/orders/_edit_amounts.html.haml index 17666c2d8..4d897d2fe 100644 --- a/app/views/orders/_edit_amounts.html.haml +++ b/app/views/orders/_edit_amounts.html.haml @@ -1,91 +1,15 @@ += render partial: 'shared/js_templates/unit_conversion_popover_template', locals: {set_units_data: true} - new_articles = (@order.supplier.articles.undeleted rescue @order.articles) -- new_article_data = articles_for_select2(new_articles, @order_articles.map(&:article_id)) {|a| "#{a.name} (#{a.unit_quantity}⨯#{a.unit})"} +- current_article_ids = @order_articles.map { |oa| oa.article_version.article_id } +- new_article_data = articles_for_select2(new_articles, current_article_ids) {|a| "#{a.name} (#{a.unit_quantity}⨯#{a.unit})"} - content_for :javascript do :javascript - - function update_delta(input) { - var units = $(input).val(); - var expected = $(input).data('units-expected'); - var delta = Math.round((units-expected)*100)/100.0; - var html; - - if (units.replace(/\s/g,"")=="") { - // no value - html = ''; - } else if (isNaN(units)) { - html = ''; - } else if (delta == 0) { - // equal value - html = ''; - } else { - if (delta < 0) { - html = '- '+(-delta)+''; - } else /*if (units> expected)*/ { - html = '+ '+(delta)+''; - } - // show package icon only if the receive field has one - if ($(input).hasClass('package')) { - html += '#{j pkg_helper_icon}'; - } - } - - $(input).closest('tr').find('.units_delta').html(html); - - // un-dim row when received is nonzero - $(input).closest('tr').toggleClass('unavailable', expected == 0 && html==''); - } - - $(document).on('change keyup', 'input[data-units-expected]', function() { - update_delta(this); - }); - - $(document).on('touchclick', '#order_articles .unlocker', unlock_receive_input_field); - - $(document).on('click', '#set_all_to_zero', function() { - $('tbody input').each(function(i, input) { - $(input).val(0); - update_delta(input); - }); - }) - - $(function() { - $('input[data-units-expected]').each(function() { - update_delta(this); - }); - - init_add_article('#add_article'); - }); - - function init_add_article(sel) { - $(sel).removeAttr('disabled').select2({ - placeholder: '#{j t('orders.receive.add_article')}', - formatNoMatches: function(term) { return '#{j t('.no_articles_available')}';} - // TODO implement adding a new article, like in deliveries - }).on('change', function(e) { - var $input = $(e.target); - var selectedArticleId = $input.val(); - if(!selectedArticleId) { - return false; - } - - $.ajax({ - url: '#{order_order_articles_path(@order)}', - type: 'post', - data: JSON.stringify({order_article: {article_id: selectedArticleId}}), - contentType: 'application/json; charset=UTF-8' - }); - - $input.val('').trigger('change'); - }); - $(sel).val('').trigger('change'); - } - - function unlock_receive_input_field() { - $('.units_received', $(this).closest('tr')).prop('disabled', false).focus(); - $(this).closest('.input-prepend').prop('title', I18n.t('orders.edit_amount.field_unlocked_title')); - $(this).replaceWith(''); - } - + $('.units_received').each((_, field) => $(field).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false + })); + $('table#order_articles').parents('form').receiveOrderForm({packageHelperIcon: '#{j pkg_helper_icon}', newOrderArticlePath:'#{order_order_articles_path(@order)}'}); %table#order_articles.ordered-articles.table.table-striped.stupidtable{style: 'margin-bottom: 0'} %thead %tr diff --git a/app/views/orders/_form.html.haml b/app/views/orders/_form.html.haml index ec3db1f30..c73aa9fe4 100644 --- a/app/views/orders/_form.html.haml +++ b/app/views/orders/_form.html.haml @@ -50,9 +50,7 @@ %td= truncate article.origin, length: 15, tooltip: true %td= truncate article.manufacturer, length: 15, tooltip: true %td - = article.unit - - if article.unit_quantity > 1 - %span{style: 'color: grey'} × #{article.unit_quantity}#{pkg_helper_icon} + = format_supplier_order_unit_with_ratios(article) %td= "#{number_to_currency(article.price)} / #{number_to_currency(article.fc_price)}" %tr %td diff --git a/app/views/orders/add_article.js.erb b/app/views/orders/add_article.js.erb index 7343d5011..e43e3a492 100644 --- a/app/views/orders/add_article.js.erb +++ b/app/views/orders/add_article.js.erb @@ -1,14 +1,14 @@ $('div.container-fluid').prepend( - '<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @order_article.article.name)})) %>' + '<%= j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @order_article.article_version.name)})) %>' ); (function() { $('.ordered-articles tr').removeClass('success'); - + var article_for_adding = $( '<%= j(render(:partial => 'edit_amount', :locals => {:order_article => @order_article})) %>' ).addClass('success'); - + $('.ordered-articles tbody').append(article_for_adding); updateSort('.ordered-articles'); diff --git a/app/views/orders/receive_on_order_article_create.js.erb b/app/views/orders/receive_on_order_article_create.js.erb index ed37975f8..464ffe1e6 100644 --- a/app/views/orders/receive_on_order_article_create.js.erb +++ b/app/views/orders/receive_on_order_article_create.js.erb @@ -2,16 +2,16 @@ // See publish/subscribe design pattern in /doc. (function(w) { $('#order_article_<%= @order_article.id %>').remove(); // just to be sure: remove table row which is added below - + $('#order_articles tr').removeClass('success'); - + var order_article_entry = $( '<%= j render(partial: 'edit_amount', locals: {order_article: @order_article}) %>' ).addClass('success'); - + $('#order_articles tbody').append(order_article_entry); updateSort('#order_articles'); - - $('#add_article_<%= @order_article.article.id %>').remove(); // remove option to add this article + + $('#add_article_<%= @order_article.article_version.id %>').remove(); // remove option to add this article })(window); diff --git a/app/views/orders/receive_on_order_article_update.js.erb b/app/views/orders/receive_on_order_article_update.js.erb index d4ee9a72d..1c8347079 100644 --- a/app/views/orders/receive_on_order_article_update.js.erb +++ b/app/views/orders/receive_on_order_article_update.js.erb @@ -1,35 +1,9 @@ // Handle more advanced DOM update after AJAX database manipulation. // See publish/subscribe design pattern in /doc. (function(w) { - // get old element and update the cell which is reused - var old_order_article_entry = $('#order_article_<%= @order_article.id %>'); - - // update package info after input - $('td.units_received_cell span.package', old_order_article_entry).remove(); - $('<%= j pkg_helper(@order_article.article_price, icon: false) %>') - .appendTo($('td.units_received_cell', old_order_article_entry)); - - // update package icon on input too - $('input', old_order_article_entry).toggleClass('package', <%= @order_article.article_price.unit_quantity == 1 ? 'false' : 'true' %>); - - // update expected units, since unit_quantity may have been changed - $('input', old_order_article_entry).data('units-expected', <%= - (@order_article.units_billed or @order_article.units_to_order) * - 1.0 * @order_article.article.unit_quantity / @order_article.article_price.unit_quantity - %>); - - // render new element and inject dynamic cell - var new_order_article_entry = $( - '<%= j render(partial: 'edit_amount', locals: {order_article: @order_article}) %>' - ); - - $('td.units_received_cell', new_order_article_entry).replaceWith( - $('td.units_received_cell', old_order_article_entry) - ); - - // finally replace the OrderArticle entry - old_order_article_entry.replaceWith(new_order_article_entry); - - update_delta($('input.units_received', new_order_article_entry)); + $('table#order_articles').parents('form').receiveOrderForm('replace', { + id: <%= @order_article.id %>, + newEntry: $('<%= j render(partial: 'edit_amount', locals: {order_article: @order_article}) %>') + }); })(window); diff --git a/app/views/orders/show.html.haml b/app/views/orders/show.html.haml index 2f730e366..612adea64 100644 --- a/app/views/orders/show.html.haml +++ b/app/views/orders/show.html.haml @@ -1,3 +1,4 @@ += render partial: 'shared/js_templates/unit_conversion_popover_template', locals: {set_units_data: true} - title t('.title', name: @order.name) - if current_user.role_finance? || current_user.role_invoices? @@ -98,3 +99,5 @@ = render 'show_js' = render 'shared/articles_by/common', order: @order + + diff --git a/app/views/orders/show.js.erb b/app/views/orders/show.js.erb index 47a69e8d9..2c29b7f3d 100644 --- a/app/views/orders/show.js.erb +++ b/app/views/orders/show.js.erb @@ -1,4 +1,11 @@ $('#articles_table').html('<%= j render(@partial, order: @order) %>'); +$('*[name="group_order_article[result]"]').each(function() { + $(this).unitConversionField({ + units: unitsData, + popoverTemplate$: $('#unit_conversion_popover_content_template'), + useTargetUnitForStep: false + }); +}); $('.view_buttons a').each(function() { $(this).toggleClass('active', $(this).attr('id') == 'view_<%= j params[:view] %>_btn'); diff --git a/app/views/shared/_article_fields_price.html.haml b/app/views/shared/_article_fields_price.html.haml index ea6ee9a2e..efe18036c 100644 --- a/app/views/shared/_article_fields_price.html.haml +++ b/app/views/shared/_article_fields_price.html.haml @@ -3,32 +3,22 @@ .input-prepend %span.add-on= t 'number.currency.format.unit' = f.input_field :price, class: 'input-mini' + = f.input :price_unit, as: :select, collection: [], input_html: {'data-initial-value': article.price_unit, class: 'input-medium'}, label: t('articles.form.per'), include_blank: false +.fold-line = f.input :tax do .input-append = f.input_field :tax, class: 'input-mini' %span.add-on % -.fold-line = f.input :deposit do .input-prepend %span.add-on= t 'number.currency.format.unit' = f.input_field :deposit, class: 'input-mini' +.fold-line .control-group %label.control-label{for: 'article_fc_price'} = Article.human_attribute_name(:fc_price) .controls.control-text#article_fc_price - = number_to_currency(f.object.fc_price) rescue nil - --# do this inline, since it's being used in ajax forms only -- field = f.object.class.model_name.to_s.underscore -:javascript - var form = $('#article_fc_price').closest('form'); - $('##{field}_price, ##{field}_tax, ##{field}_deposit', form).on('change keyup', function() { - var price = parseFloat($('##{field}_price', form).val()); - var tax = parseFloat($('##{field}_tax', form).val()); - var deposit = parseFloat($('##{field}_deposit', form).val()); - // Article#gross_price and Article#fc_price - var gross_price = (price + deposit) * (tax / 100 + 1); - var fc_price = gross_price * (#{FoodsoftConfig[:price_markup].to_f} / 100 + 1); - $('#article_fc_price').html($.isNumeric(fc_price) ? I18n.l("currency", fc_price) : '…'); - }); + %span.price_value + %span.price_per_text=t('articles.form.per') + %span.price_unit diff --git a/app/views/shared/_article_fields_units.html.haml b/app/views/shared/_article_fields_units.html.haml index b9704cef0..77914413b 100644 --- a/app/views/shared/_article_fields_units.html.haml +++ b/app/views/shared/_article_fields_units.html.haml @@ -1,6 +1,33 @@ --# use the local 'f', or supply 'f_uq' and 'f_unit' for more control (like in balancing) +-# var parcel = $($.parseHTML("#{escape_javascript(render('shared/parcel'))}")); +-# var parcels = #{raw @parcels.to_json}; + +.fold-line.d-flex + = f.hidden_field :unit, id: 'article_unit_hidden', value: '' + -# title: unit in which article can be ordered from supplier + - supplier_order_unit_override = article.supplier_order_unit + - supplier_order_unit_override = 'XPP' if supplier_order_unit_override.nil? && article.unit.nil? + = f.input :supplier_order_unit, as: :select, collection: @article_units, selected: supplier_order_unit_override, include_blank: t('.custom_unit'), input_html: {class: 'input-medium'} + -# title: free text unit + = f.input :unit, input_html: {class: 'input-mini ml-1', placeholder: t('.unit')}, label: false + %i.icon-warning-sign{title: t('.warn_about_needless_custom_unit')} .fold-line - = (f_uq rescue f).input :unit_quantity, label: Article.human_attribute_name(:unit), - input_html: {class: 'input-mini', title: Article.human_attribute_name(:unit_quantity)} - = (f_unit rescue f).input :unit, label: '×'.html_safe, - input_html: {class: 'input-mini', title: Article.human_attribute_name(:unit)} + .control-group + %label.control-label + = t('.unit_ratios') + %table#fc_base_price{:class => "controls"} + %tbody + - ratios = article.article_unit_ratios + = render :partial => 'shared/article_unit_ratio', :as => 'article_unit_ratio', :collection => ratios, locals: {f: f} + %tfoot + %td{:colspan => 6} + = link_to t('.add_ratio'), '#', 'data-add-ratio' => true, class: 'btn', title: "add ratio" +.fold-line + = f.input :minimum_order_quantity do + .input-append + = f.input_field :minimum_order_quantity, class: 'input-mini' + %span.add-on +.fold-line + = f.input :billing_unit, as: :select, collection: [], input_html: {'data-initial-value': article.billing_unit, class: 'input-medium'}, include_blank: false +.fold-line + = f.input :group_order_granularity, input_html: {class: 'input-mini', step: 0.001} + = f.input :group_order_unit, as: :select, collection: [], input_html: {'data-initial-value': article.group_order_unit, class: 'input-medium'}, label: '×'.html_safe, include_blank: false diff --git a/app/views/shared/_article_unit_ratio.haml b/app/views/shared/_article_unit_ratio.haml new file mode 100644 index 000000000..a45329339 --- /dev/null +++ b/app/views/shared/_article_unit_ratio.haml @@ -0,0 +1,19 @@ +- original_ratio = defined?(original_ratios) ? original_ratios&.to_a&.dig(article_unit_ratio_counter) : nil +- changed = !original_ratio.nil? && (original_ratio.quantity != article_unit_ratio.quantity || original_ratio.unit != article_unit_ratio.unit) +%tr{:class => 'no-indent-left', :style => changed ? "background-color: yellow" : ""} + = f.fields_for(:article_unit_ratios, article_unit_ratio) do |sub_form| + -# title: unit quantifier + %td + -# TODO: Check, if there was any justified reason for this article_unit_ratio_counter logic: + -#= hidden_field f.object.class.to_s.underscore + "[article_unit_ratios_attributes][#{article_unit_ratio_counter + 1}]", :sort, value: article_unit_ratio_counter + 1 + = sub_form.input :sort, as: :hidden + + = sub_form.input :quantity, {input_html: {class: 'input-mini'}, label: false} + %td= '×'.html_safe + %td= sub_form.input :unit, as: :select, include_blank: true, collection: @article_units, label: false, input_html: {class: 'input-medium'} + %td.ml-1= t('.per') + %td + %span.unit_multiplier.mr-1 + %td.actions{style: 'width:1em'} + = link_to t('.remove'), method: :delete, 'data-remove-ratio' => true, title: t('.remove'), class: 'btn btn-danger btn-mini' do + = glyph :remove diff --git a/app/views/shared/_article_price_info.html.haml b/app/views/shared/_article_version_info.html.haml similarity index 100% rename from app/views/shared/_article_price_info.html.haml rename to app/views/shared/_article_version_info.html.haml diff --git a/app/views/shared/articles_by/_article_single.html.haml b/app/views/shared/articles_by/_article_single.html.haml index 6c563d64e..6e8aa352d 100644 --- a/app/views/shared/articles_by/_article_single.html.haml +++ b/app/views/shared/articles_by/_article_single.html.haml @@ -3,11 +3,9 @@ %tr.list-heading %th{:colspan => "4"}> %h4.name.pull-left - = order_article.article.name + - article_version = order_article.article_version + = article_version.name %small - = "(#{order_article.article.unit}, #{number_to_currency order_article.price.fc_price}" - - pkg_info = pkg_helper(order_article.price) - = ", #{pkg_info}".html_safe unless pkg_info.blank? - ) + = "#{format_billing_unit_with_ratios(article_version)}, #{number_to_currency(article_version.convert_quantity(article_version.fc_price, article_version.billing_unit, article_version.supplier_order_unit))}" - for goa in order_article.group_order_articles.ordered = render 'shared/articles_by/article_single_goa', goa: goa diff --git a/app/views/shared/articles_by/_article_single_goa.html.haml b/app/views/shared/articles_by/_article_single_goa.html.haml index 1f7270074..a791ae08f 100644 --- a/app/views/shared/articles_by/_article_single_goa.html.haml +++ b/app/views/shared/articles_by/_article_single_goa.html.haml @@ -1,5 +1,6 @@ %tr{class: if goa.result == 0 then 'unavailable' end, id: "goa_#{goa.id}"} + - article_version = goa.order_article.article_version %td{:style => "width:70%"}= goa.group_order.ordergroup_name - %td.center= "#{goa.quantity} + #{goa.tolerance}" + %td.center= "#{number_with_precision(article_version.convert_quantity(goa.quantity, article_version.group_order_unit, article_version.billing_unit), precision: 3, strip_insignificant_zeros: true)} + #{number_with_precision(article_version.convert_quantity(goa.tolerance, article_version.group_order_unit, article_version.billing_unit), precision: 3, strip_insignificant_zeros: true)}" %td.center.input-delta= group_order_article_edit_result(goa) %td.price{data: {value: goa.total_price}}= number_to_currency(goa.total_price) diff --git a/app/views/shared/articles_by/_articles.html.haml b/app/views/shared/articles_by/_articles.html.haml index c2bb06957..a1e8d44c3 100644 --- a/app/views/shared/articles_by/_articles.html.haml +++ b/app/views/shared/articles_by/_articles.html.haml @@ -8,7 +8,7 @@ %acronym{:title => t('shared.articles.received_desc')}= t 'shared.articles.received' %th= t 'shared.articles_by.price' - - for order_article in order.order_articles.ordered.includes([:article, :article_price]) + - for order_article in order.order_articles.ordered.includes(:article_version) = render 'shared/articles_by/article_single', order_article: order_article %tr %td{colspan: 4} diff --git a/app/views/shared/articles_by/_group_single_goa.html.haml b/app/views/shared/articles_by/_group_single_goa.html.haml index 881891262..dfbbe925b 100644 --- a/app/views/shared/articles_by/_group_single_goa.html.haml +++ b/app/views/shared/articles_by/_group_single_goa.html.haml @@ -1,10 +1,10 @@ %tr{class: [cycle('even', 'odd', :name => 'articles'), if goa.result == 0 then 'unavailable' end], id: "goa_#{goa.id}"} - %td.name= goa.order_article.article.name - %td= goa.order_article.article.unit - %td.center= "#{goa.quantity} + #{goa.tolerance}" + - article_version = goa.order_article.article_version + %td.name= goa.order_article.article_version.name + %td= format_billing_unit_with_ratios(article_version) + %td.center= "#{number_with_precision(article_version.convert_quantity(goa.quantity, article_version.group_order_unit, article_version.billing_unit), precision: 3, strip_insignificant_zeros: true)} + #{number_with_precision(article_version.convert_quantity(goa.tolerance, article_version.group_order_unit, article_version.billing_unit), precision: 3, strip_insignificant_zeros: true)}" %td.center.input-delta= group_order_article_edit_result(goa) %td.symbol × - %td= number_to_currency(goa.order_article.price.fc_price) + %td= number_to_currency(article_version.convert_quantity(article_version.fc_price, article_version.billing_unit, article_version.supplier_order_unit)) %td.symbol = %td.price{data: {value: goa.total_price}}= number_to_currency(goa.total_price) - %td= pkg_helper goa.order_article.price diff --git a/app/views/shared/articles_by/_groups.html.haml b/app/views/shared/articles_by/_groups.html.haml index 4bd9c2854..8787a5038 100644 --- a/app/views/shared/articles_by/_groups.html.haml +++ b/app/views/shared/articles_by/_groups.html.haml @@ -11,7 +11,6 @@ %th= heading_helper Article, :fc_price, short: true %th.symbol %th= t 'shared.articles_by.price' - %th= #heading_helper Article, :unit_quantity, short: true - for group_order in order.group_orders.ordered = render 'shared/articles_by/group_single', group_order: group_order diff --git a/app/views/shared/js_templates/_unit_conversion_popover_template.haml b/app/views/shared/js_templates/_unit_conversion_popover_template.haml new file mode 100644 index 000000000..60dba287d --- /dev/null +++ b/app/views/shared/js_templates/_unit_conversion_popover_template.haml @@ -0,0 +1,12 @@ +- if defined?(set_units_data) && set_units_data + - content_for :javascript do + :javascript + const unitsData = #{raw(ArticleUnit.as_hash.to_json)}; +%template#unit_conversion_popover_content_template + %div.popover_contents.text-right{"data-title" => t('helpers.unit_conversion_fields.title'), "data-disabled-title" => t('helpers.unit_conversion_fields.disabled_title')} + .d-flex + %select.unit.mr-1{"data-ignore-onchange" => true} + %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/app/views/stock_takings/_stock_change.html.haml b/app/views/stock_takings/_stock_change.html.haml index c82bd2328..313fec662 100644 --- a/app/views/stock_takings/_stock_change.html.haml +++ b/app/views/stock_takings/_stock_change.html.haml @@ -4,6 +4,6 @@ = StockArticle.human_attribute_name :amount (#{stock_change.stock_article.quantity_available}) = form.text_field :quantity, :size => 5, :autocomplete => 'off' - %span{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_price_info', :locals => {:article => stock_change.stock_article})}"}} + %span{:data => {:toggle => :tooltip, :title => "#{render(:partial => 'shared/article_version_info', :locals => {:article => stock_change.stock_article})}"}} %b= stock_change.stock_article.name = "(#{number_to_currency(stock_change.stock_article.price)} / #{stock_change.stock_article.unit})" diff --git a/app/views/stockit/_form.html.haml b/app/views/stockit/_form.html.haml index 9048b5a11..83a7b8a79 100644 --- a/app/views/stockit/_form.html.haml +++ b/app/views/stockit/_form.html.haml @@ -1,11 +1,34 @@ -= simple_form_for stock_article, remote: true, :validate => true do |f| += simple_form_for stock_article.latest_article_version, :url => stock_article.new_record? ? stock_articles_path(stock_article, foodcoop: FoodsoftConfig.scope) : stock_article_path(stock_article), remote: true, validate: true do |f| + :javascript + const articleUnitRatioTemplate$ = $($.parseHTML("#{escape_javascript(render(partial: 'shared/article_unit_ratio', locals: {article_unit_ratio: @empty_article_unit_ratio, f: f, article_unit_ratio_counter: -1}))}")); + const units = #{raw(@all_units.to_json)}; + new ArticleForm(articleUnitRatioTemplate$, $('.article-form').parents('form'), units, #{FoodsoftConfig[:price_markup].to_f}); + = render partial: 'shared/js_templates/unit_conversion_popover_template' .modal-header = close_button :modal %h3= title - .modal-body - = f.association :supplier + .modal-body.article-form + = f.hidden_field :id + = f.simple_fields_for :article do |a| + = a.input :supplier_id, collection: Supplier.all, selected: stock_article.supplier_id = f.input :name - = f.input :unit + .fold-line.d-flex + = f.hidden_field :unit, id: 'article_unit_hidden', value: '' + -# title: unit in which article can be ordered from supplier + = f.input :supplier_order_unit, as: :select, collection: @article_units, value: stock_article.supplier_order_unit, include_blank: t('.custom_unit'), input_html: {class: 'input-medium'} + -# title: free text unit + = f.input :unit, input_html: {class: 'input-mini ml-1'}, label: false + .fold-line + .control-group + %label.control-label{for: 'unit_ratios'} + = "Unit ratios" + %table#fc_base_price{:class => "controls"} + %tbody + - ratios = stock_article.article_unit_ratios + = render :partial => 'shared/article_unit_ratio', :as => 'article_unit_ratio', :collection => ratios, locals: {f: f} + %tfoot + %td{:colspan => 6} + = link_to t('.add_ratio'), '#', 'data-add-ratio' => true, class: 'btn', title: "add ratio" = f.input :note - if stock_article.new_record? = f.input :price diff --git a/app/views/stockit/_stock_article.html.haml b/app/views/stockit/_stock_article.html.haml index 4df323421..789fefe93 100644 --- a/app/views/stockit/_stock_article.html.haml +++ b/app/views/stockit/_stock_article.html.haml @@ -3,7 +3,7 @@ %td= stock_article.quantity %td= stock_article.quantity_ordered %td.main_info= stock_article.quantity_available - %td= stock_article.unit + %td= format_supplier_order_unit(stock_article) %td= stock_article.price %td= number_to_percentage stock_article.tax %td= link_to stock_article.supplier.name, stock_article.supplier diff --git a/app/views/supplier_shares/_share_link.html.haml b/app/views/supplier_shares/_share_link.html.haml new file mode 100644 index 000000000..b0fce48ce --- /dev/null +++ b/app/views/supplier_shares/_share_link.html.haml @@ -0,0 +1,16 @@ +- if external_uuid.nil? + = t('.not_shared') +- else + - share_url = api_v1_shared_supplier_articles_url(external_uuid) + %div#copy-share-link-button.user-select-none{:role => 'button'} + %span= share_url + %i.icon-copy + + :javascript + document + .getElementById('copy-share-link-button') + .addEventListener('click', () => { + navigator.clipboard.writeText('#{share_url}'); + alert('#{t(".share_link_copied_to_clipboard")}'); + }); + diff --git a/app/views/supplier_shares/update.js.haml b/app/views/supplier_shares/update.js.haml new file mode 100644 index 000000000..caf08dbae --- /dev/null +++ b/app/views/supplier_shares/update.js.haml @@ -0,0 +1,2 @@ +$('#share_link').html('#{j(render(partial: 'share_link', locals: {external_uuid: @supplier.external_uuid}))}'); +$('.btn.share').toggle(); diff --git a/app/views/suppliers/_form.html.haml b/app/views/suppliers/_form.html.haml index d8d94d9df..3099b5137 100644 --- a/app/views/suppliers/_form.html.haml +++ b/app/views/suppliers/_form.html.haml @@ -1,8 +1,4 @@ = simple_form_for @supplier do |f| - - if @supplier.shared_supplier - .alert.alert-info - = t 'suppliers.shared_supplier_note' - = f.hidden_field :shared_supplier_id = f.input :name = f.input :address = f.input :phone @@ -21,9 +17,9 @@ = f.input :order_howto, as: :text, input_html: {rows: 5} = f.input :note, as: :text, input_html: {rows: 5} = f.input :min_order_quantity + = f.input :supplier_remote_source = render 'shared/custom_form_fields', f: f, type: :supplier - - if @supplier.shared_supplier - = f.input :shared_sync_method, collection: shared_sync_method_collection(@supplier.shared_supplier), input_html: {class: 'input-xlarge'}, include_blank: false, disabled: @supplier.shared_supplier.shared_sync_methods.count < 2 + = f.input :shared_sync_method, collection: shared_sync_method_collection, input_html: {class: 'input-xlarge'}, include_blank: true .form-actions = f.submit class: 'btn' = link_to t('ui.or_cancel'), suppliers_path diff --git a/app/views/suppliers/_import_search_results.haml b/app/views/suppliers/_import_search_results.haml new file mode 100644 index 000000000..cbc6bbc85 --- /dev/null +++ b/app/views/suppliers/_import_search_results.haml @@ -0,0 +1,29 @@ +- if @articles.empty? + %p= t '.not_found' +- else + = pagination_links_remote @pagination + %table.table.table-striped + %thead + %tr + %th= heading_helper Article, :name + %th= heading_helper Article, :origin + %th= heading_helper Article, :manufacturer + %th= heading_helper Article, :note + %th{:style => "width:4em"}= heading_helper Article, :price + %th= heading_helper Article, :supplier_order_unit + %th + %tbody + - @articles.each_with_index do |article, index| + %tr + %td= highlight article[:name], params.fetch(:name, '').split(' ') + %td= article[:origin] + %td= article[:manufacturer] + %td{title: article[:note]}= truncate(article[:note], length: 11) + %td= number_to_currency(article[:price]) + %td= ArticleUnitsLib.get_translated_name_for_code(article[:supplier_order_unit]) + %td.actions.import-actions{:data => {order_number: article[:order_number]}} + - article_exists = @supplier.articles.includes(:latest_article_version).undeleted.where(article_versions: {order_number: article[:order_number]}).exists? + %i.icon-ok{:style => article_exists ? '' : 'display:none;'}= t '.already_imported' + = link_to t('.action_import'), supplier_articles_path(@supplier), + remote: true, class: 'btn btn-small btn-success article_import_btn', data: {index: index}, + style: article_exists ? 'display:none;' : '' diff --git a/app/views/suppliers/index.html.haml b/app/views/suppliers/index.html.haml index 9e4c3870f..ab90257f7 100644 --- a/app/views/suppliers/index.html.haml +++ b/app/views/suppliers/index.html.haml @@ -2,8 +2,6 @@ - content_for :actionbar do = link_to t('.action_new'), new_supplier_path, class: 'btn btn-primary' - - if FoodsoftConfig[:shared_lists] - = link_to t('.action_import'), shared_suppliers_suppliers_path, class: 'btn' %table.table.table-striped %thead %tr diff --git a/app/views/suppliers/remote_articles.js.haml b/app/views/suppliers/remote_articles.js.haml new file mode 100644 index 000000000..06a72b9f8 --- /dev/null +++ b/app/views/suppliers/remote_articles.js.haml @@ -0,0 +1,22 @@ +:plain + $('#search_results').html("#{j(render("import_search_results"))}"); + const remoteArticleData = #{raw(@articles.to_json)}; + $("#search_results .article_import_btn").click(function(e) { + e.preventDefault(); + e.stopPropagation(); + const index = $(this).data('index'); + const article = remoteArticleData[index]; + const categoryId = $('#import #article_category_id').children(':selected').val(); + if (categoryId !== '') { + article.article_category_id = categoryId; + } + article.article_unit_ratios_attributes = article.article_unit_ratios; + delete article.article_unit_ratios; + delete article.created_at; + delete article.updated_at; + $.post($(this).attr('href'), {article_version: article}, + function(result) { + alter('success', result); + } + ); + }); diff --git a/app/views/suppliers/shared_suppliers.html.haml b/app/views/suppliers/shared_suppliers.html.haml deleted file mode 100644 index 8e9c3eeff..000000000 --- a/app/views/suppliers/shared_suppliers.html.haml +++ /dev/null @@ -1,25 +0,0 @@ -- title t('.title') -= t('.body').html_safe - -%table.table.table-striped - %thead - %tr - %th= heading_helper Supplier, :name - %th= heading_helper Supplier, :address - %th= heading_helper Supplier, :note - %th= heading_helper Supplier, :delivery_days - %th= heading_helper Supplier, :is_subscribed - %tbody - - for shared_supplier in @shared_suppliers - %tr - %td= shared_supplier.name - %td= shared_supplier.address - %td= shared_supplier.note - %td= shared_supplier.delivery_days - %td - - if shared_supplier.suppliers.any? - %i.icon-ok - = associated_supplier_names(shared_supplier) - = link_to t('.subscribe_again'), new_supplier_path(:shared_supplier_id => shared_supplier), class: 'btn' - - else - = link_to t('.subscribe'), new_supplier_path(:shared_supplier_id => shared_supplier), class: 'btn' diff --git a/app/views/suppliers/show.html.haml b/app/views/suppliers/show.html.haml index c3fbe4c4d..db506c957 100644 --- a/app/views/suppliers/show.html.haml +++ b/app/views/suppliers/show.html.haml @@ -7,7 +7,7 @@ .row-fluid .span6 - - if shared_supplier = @supplier.shared_supplier + - unless @supplier.shared_sync_method.nil? .alert.alert-info = t 'suppliers.shared_supplier_note' = t "suppliers.shared_supplier_methods.#{@supplier.shared_sync_method}" @@ -43,6 +43,11 @@ %dd= simple_format(@supplier.note) %dt= heading_helper(Supplier, :min_order_quantity) + ':' %dd= @supplier.min_order_quantity + %dt= heading_helper(Supplier, :share_link) + ':' + %dd + %div#share_link= render partial: 'supplier_shares/share_link', locals: { external_uuid: @supplier.external_uuid } + = link_to t('.share'), supplier_share_path(@supplier), remote: true, class: 'btn share', method: :post, style: @supplier.external_uuid.nil? ? nil : 'display: none;' + = link_to t('.remove_share'), supplier_share_path(@supplier), remote: true, class: 'btn share', method: :delete, data: { confirm: t('.confirm_remove_share') }, style: @supplier.external_uuid.nil? ? 'display: none;' : nil .clearfix - if @current_user.role_suppliers? diff --git a/bin/autospec b/bin/autospec index 64dcb9cb0..602d5c828 100755 --- a/bin/autospec +++ b/bin/autospec @@ -7,8 +7,8 @@ # require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) require 'rubygems' require 'bundler/setup' diff --git a/bin/mailcatcher b/bin/mailcatcher index a4b2c2480..67d7b0363 100755 --- a/bin/mailcatcher +++ b/bin/mailcatcher @@ -7,8 +7,8 @@ # require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) require 'rubygems' require 'bundler/setup' diff --git a/bin/resque b/bin/resque index 2e40831b1..f018141c9 100755 --- a/bin/resque +++ b/bin/resque @@ -7,8 +7,8 @@ # require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) require 'rubygems' require 'bundler/setup' diff --git a/bin/resque-web b/bin/resque-web index b49543cd2..22ad07e0e 100755 --- a/bin/resque-web +++ b/bin/resque-web @@ -7,8 +7,8 @@ # require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) require 'rubygems' require 'bundler/setup' diff --git a/bin/rspec b/bin/rspec index 0c86b5c6f..8bc84617e 100755 --- a/bin/rspec +++ b/bin/rspec @@ -7,8 +7,8 @@ # require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) require 'rubygems' require 'bundler/setup' diff --git a/bin/yarn b/bin/yarn index 460dd565b..d3627c34c 100755 --- a/bin/yarn +++ b/bin/yarn @@ -1,11 +1,9 @@ #!/usr/bin/env ruby APP_ROOT = File.expand_path('..', __dir__) Dir.chdir(APP_ROOT) do - begin - exec "yarnpkg", *ARGV - rescue Errno::ENOENT - $stderr.puts "Yarn executable was not detected in the system." - $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" - exit 1 - end + exec 'yarnpkg', *ARGV +rescue Errno::ENOENT + warn 'Yarn executable was not detected in the system.' + warn 'Download Yarn at https://yarnpkg.com/en/docs/install' + exit 1 end diff --git a/config/i18n-js.yml b/config/i18n-js.yml index 1631dc1b9..3f0e650c8 100644 --- a/config/i18n-js.yml +++ b/config/i18n-js.yml @@ -7,5 +7,7 @@ translations: '*.number.*', '*.date.formats.*', # foodsoft-specific texts to keep js with normal translations - '*.orders.edit_amount.*' + '*.orders.edit_amount.*', + '*.orders.receive.*', + 'no_articles_available' ] diff --git a/config/locales/de.yml b/config/locales/de.yml index 68e01b143..b55e91c6e 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -22,17 +22,44 @@ de: supplier: Lieferantin tax: MwSt unit: Einheit + custom_unit: Benutzerdefinierte Einheit unit_quantity: Gebindegröße unit_quantity_short: GebGr units: Gebinde + supplier_order_unit: von Lieferantin bestellbar in (Einheit) + ratios_to_supplier_order_unit: Inhalt + minimum_order_quantity: Mindestbestellmenge + billing_unit: abgerechnet nach (Einheit) + group_order_granularity: für Mitglieder bestellbar in (Menge) + group_order_unit: für Mitglieder bestellbar in (Einheit) + price_unit: pro (Preiseinheit) + article_unit: + code: Einheitencode gemäß Empfehlung der United Nations Economic Commission (UNECE) + code_short: Code + symbol: Einheitenzeichen + description: Beschreibung (Englisch) article_category: description: Beschreibung name: Name - article_price: + article_version: deposit: Pfand price: Nettopreis tax: MwSt unit_quantity: Gebindegröße + + availability: Artikel ist verfügbar? + name: Name + note: Notiz + origin: Herkunft + manufacturer: Produzent + order_number: Bestellnummer + article_category: Kategorie + + supplier_order_unit: Liefereinheit + group_order_granularity: bestellbar per + billing_unit: Abrechnungseinheit + price_unit: Preiseinheit + minimum_order_quantity: Mindestbestellmenge bank_account: balance: Kontostand bank_gateway: Bankgateway @@ -138,6 +165,7 @@ de: updated_by: Zuletzt geändert von order_article: article: Artikel + article_version: Artikel missing_units: Fehlende Einheiten missing_units_short: Fehlend quantity: Gewünschte Einheiten @@ -239,11 +267,13 @@ de: errors: has_many_left: ist noch mit einem/r %{collection} verknüpft! models: - article: + article_version: attributes: name: taken: Name ist bereits vergeben taken_with_unit: Name und Einheit sind bereits vergeben + minimum_order_quantity: + only_integer: Muss eine Ganzzahl sein, wenn die Liefereinheit eine Stückeinheit ist. supplier: attributes: shared_sync_method: @@ -254,6 +284,7 @@ de: exclusion: erledigte Aufgaben können nicht wöchentlich wiederholt werden models: article: Artikel + article_version: Artikel article_category: Kategorie bank_account: Bankkonto bank_gateway: Bankgateway @@ -481,14 +512,10 @@ de: notice: "Es wurden %{count} neue Artikel gespeichert." error_invalid: Artikel sind fehlerhaft error_nosel: Du hast keine Artikel ausgewählt - error_parse: "%{msg} ... in Zeile %{line}" error_update: 'Es trat ein Fehler beim Aktualisieren des Artikels ''%{article}'' auf: %{msg}' parse_upload: no_file: Bitte eine Datei zum hochladen auswählen. notice: "%{count} Artikel sind erfolgreich analysiert." - sync: - notice: Der Katalog ist aktuell - shared_alert: "%{supplier} ist nicht mit einer externen Datenbank verknüpft." update_all: notice: Alle Artikel und Preise wurden aktualisiert update_sel: @@ -498,6 +525,8 @@ de: notice_unavail: Alle gewählten Artikel wurden auf "nicht verfügbar" gesetzt update_sync: notice: Alle Artikel und Preise wurden aktualisiert + complete_units_migration: + notice: Artikel erfolgreich migriert destroy_active_article: drop: entfernen note: "%{article} wird in laufenden Bestellungen verwendet und kann nicht gelöscht werden. Bitte zuerst den Artikel aus den Bestellungen %{drop_link}." @@ -509,14 +538,12 @@ de: form: title_edit: Artikel bearbeiten title_new: Neuen Artikel einfügen - import_search_results: - action_import: importieren - already_imported: schon importiert - not_found: Keine Artikel gefunden + per: pro index: change_supplier: Lieferant wechseln download: Artikel herunterladen edit_all: Alle bearbeiten + migrate_units: Alte Artikeleinheiten migrieren ext_db: import: Suchen/Importieren sync: Synchronisieren @@ -530,6 +557,22 @@ de: search_placeholder: Name ... title: Artikel von %{supplier} (%{count}) upload: Artikel hochladen + prepare_units_migration: + title: Artikel von %{supplier} migrieren + explanation: | + Es wird sehr empfohlen ein Backup herunterzuladen ehe Sie fortfahren: + download: Artikel-Backup herunterladen + migrate_units: Nächster Schritt + migrate_units: + title: Artikel von %{supplier} migrieren + explanation: | + Die Artikeleinheiten werden nun in eine neue, flexiblere Form konvertiert. Passen Sie die Konvertierungsvorschläge an, ehe sie fortfahren. + column_headers: + apply: Konvertieren + original_plaintext_unit: Ursprüngliche Volltext-Einheit + affected_articles: Betroffene Artikel + contains: Beinhaltet + run_migration: Migration jetzt durchführen model: error_in_use: "%{article} kann nicht gelöscht werden. Der Artikel befindet sich in einer laufenden Bestellung!" error_nosel: Du hast keine Artikel ausgewählt @@ -762,9 +805,8 @@ de: rows: - BestellNr. - Menge - - Name - - Gebinde - Einheit + - Name - Preis/Einheit - Summe total: Gesamtpreis @@ -783,6 +825,15 @@ 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! + new: + first_paragraph: Fehler gefunden? Vorschlag? Idee? Kritik? Wir freuen uns über jegliches Feedback. + second_paragraph: Bitte beachte, dass das Foodsoft Team nur die Software wartet. Bei Fragen zur Organisation in Deiner Foodcoop, kontaktiere besser die entsprechenden Ansprechpartner. + send: Absenden + title: Gib Feedback finance: balancing: close: @@ -1137,6 +1188,11 @@ de: tasks: required_users: "Es fehlen %{count} Mitstreiterinnen!" task_title: "%{name} (%{duration}h)" + unit_conversion_fields: + title: Einheiten umrechnen + disabled_title: Einheit kann nicht konvertiert werden + cancel: Abbrechen + apply: Anwenden home: apple_bar: desc: 'Abgebildet ist das Verhältnis von erledigten Aufgaben zu dem Bestellvolumen Deiner Bestellgruppe im Vergleich zum Durchschnitt in der Foodcoop. Konkret: Pro %{amount} Bestellsumme solltest Du eine Aufgabe machen!' @@ -1424,6 +1480,7 @@ de: stock: Lager suppliers: Lieferanten/Artikel title: Artikel + article_units: Artikeleinheiten dashboard: Übersichtsseite finances: accounts: Konten verwalten @@ -1485,6 +1542,7 @@ de: heading: Bestellung für %{name} name: Name number: Nummer + unit: Einheit to_address: Versandaddresse finish: notice: Die Bestellung wurde beendet. @@ -1602,6 +1660,15 @@ de: ordered_desc: Anzahl der Artikel die durch das Mitglied bestellt wurden (Menge + Toleranz) received: Bekommen received_desc: Anzahl der Artikel die ein Mitglied erhält + article_fields_units: + custom_unit: Benutzerdefiniert + unit: Einheit + unit_ratios: Einheiten-Umrechnung + add_ratio: Umrechnung hinzufügen + warn_about_needless_custom_unit: Wenn möglich keine benutzerdefinierten Einheiten eintippen, sondern stattdessen das Einheiten-Dropdown verwenden (Das gewährleistet Interoperabilität mit anderen Systemen und erlaubt die automatische Umrechnung in andere Einheiten.) + article_unit_ratio: + remove: Umrechnung entfernen + per: pro articles_by: price: Gesamtpreis price_sum: Summe @@ -1766,6 +1833,21 @@ de: stock_changes: Verlauf des Lagerbestands update: notice: Lagerartikel »%{name}« aktualisiert. + article_units: + index: + search: Einheit/Symbol suchen + only_recommended: Nur empfohlene + rows: + request_translation: Für diese Einheit existiert noch keine Übersetzung. Wenn Sie der Meinung sind, dass es eine gebräuchliche Einheit ist, klicken Sie hier um ein neues GitHub Issue zu erstellen. + create_link: + add: Hinzufügen + destroy_link: + delete: Entfernen + confirm: Wollen Sie die Artikeleinheit wirklich entfernen? (Bestehende Artikel, die diese Einheit verwenden, werden nicht verändert, aber man kann die Einheit dann nicht mehr in neuen Artikeln verwenden.) + create: + success: Artikeleinheit %{name} erfolgreich hinzugefügt. + destroy: + success: Artikeleinheit %{name} erfolgreich entfernt. suppliers: create: notice: Lieferant wurde erstellt @@ -1799,8 +1881,19 @@ de: last_orders: Letzte Bestellungen new_delivery: Neue Lieferung anlegen show_deliveries: Zeige alle Lieferungen + share: Teilen + remove_share: Nicht mehr teilen + confirm_remove_share: Willst Du wirklich aufhören die Artikel dieser Lieferantin zu teilen? (Wenn Du sie später wieder freigeben willst, musst du den Link an alle Abonnentinnen schicken, die deiner Meinung nach Zugriff haben sollten.) update: notice: Lieferant wurde aktualisiert + import_search_results: + action_import: importieren + already_imported: schon importiert + not_found: Keine Artikel gefunden + supplier_shares: + share_link: + not_shared: Die Artikel der Lieferantin werden aktuell mit niemandem geteilt. + share_link_copied_to_clipboard: Link zum Teilen in die Zwischenablage kopiert. tasks: accept: notice: Du hast die Aufgabe übernommen diff --git a/config/locales/en.yml b/config/locales/en.yml index a863a670b..0b21fee3a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -22,17 +22,46 @@ en: supplier: Supplier tax: VAT unit: Unit + custom_unit: Custom unit unit_quantity: Unit quantity unit_quantity_short: U.Q. units: Units + supplier_order_unit: orderable from supplier per (unit) + ratios_to_supplier_order_unit: Content + minimum_order_quantity: Minimum order quantity + billing_unit: billed per (unit) + group_order_granularity: members can order per (amount) + group_order_unit: members can order per (unit) + price_unit: per (price unit) + + article_unit: + code: Unit code according to the recommendation of the United Nations Economic Commission (UNECE) + code_short: Code + symbol: Symbol + description: Description article_category: description: Import names name: Name - article_price: + article_version: deposit: Deposit price: Price (net) tax: VAT unit_quantity: Unit quantity + + + availability: Is article available? + name: Name + note: Note + origin: Origin + manufacturer: Manufacturer + order_number: Order number + article_category: Category + + supplier_order_unit: Delivery unit + group_order_granularity: can be ordered per + billing_unit: Billing unit + price_unit: Price unit + minimum_order_quantity: Minimum order quantity bank_account: balance: Balance bank_gateway: Bank gateway @@ -138,6 +167,7 @@ en: updated_by: Last edited by order_article: article: Article + article_version: Article missing_units: Missing units missing_units_short: Missing quantity: Desired amount @@ -239,11 +269,13 @@ en: errors: has_many_left: is still associated with a %{collection}! models: - article: + article_version: attributes: name: taken: name is already taken taken_with_unit: name and unit are already taken + minimum_order_quantity: + only_integer: Must be an integer if supplier order unit is a piece unit supplier: attributes: shared_sync_method: @@ -254,6 +286,7 @@ en: exclusion: finished tasks may not be repeated models: article: Article + article_version: Article article_category: Category bank_account: Bank account bank_gateway: Bank gateway @@ -481,14 +514,10 @@ en: notice: "%{count} new articles were saved." error_invalid: There are errors in articles error_nosel: No articles selected - error_parse: "%{msg} ... in line %{line}" error_update: 'An error occured when updating article ''%{article}'': %{msg}' parse_upload: no_file: Please select a file to upload. notice: "%{count} articles were succesfully analysed." - sync: - notice: Catalog is up to date - shared_alert: "%{supplier} is not linked to an external database" update_all: notice: All articles and prices were updated. update_sel: @@ -498,6 +527,8 @@ en: notice_unavail: All selected articles were set to be unavailable. update_sync: notice: All articles and prices were updated. + complete_units_migration: + notice: Articles successfully migrated destroy_active_article: drop: delete note: "%{article} is used in current orders and can not be deleted Please first ... the article from orders %{drop_link}." @@ -509,14 +540,12 @@ en: form: title_edit: Edit article title_new: Add new article - import_search_results: - action_import: import - already_imported: imported - not_found: No articles found + per: per index: change_supplier: Change supplier download: Download articles edit_all: Edit all + migrate_units: Migrate old article units ext_db: import: Import article sync: Synchronise @@ -530,6 +559,22 @@ en: search_placeholder: Name ... title: Articles from %{supplier} (%{count}) upload: Upload articles + prepare_units_migration: + explanation: | + It's highly recommended to download a backup before continuing: + title: Migrate articles of %{supplier} + download: Download articles backup + migrate_units: Next step + migrate_units: + title: Migrate articles of %{supplier} + explanation: | + This will try to migrate articles to their new, more versatile format. You may adapt the suggested changes before continuing if you see fit. + column_headers: + apply: Convert + original_plaintext_unit: Original plaintext unit + affected_articles: Affected articles + contains: Contains + run_migration: Run migration now model: error_in_use: "%{article} can not be deleted because the article is part of a current order!" error_nosel: You have selected no articles @@ -762,9 +807,8 @@ en: rows: - Order Number - Amount - - Name - - Unit quantity - Unit + - Name - Price/Unit - Subtotal total: Total @@ -783,6 +827,15 @@ 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! + new: + first_paragraph: Found a bug? Suggestions? Ideas? Reviews? We are happy to hear any feedback. + second_paragraph: Please be aware that the Foodsoft Team is only responsible for the maintenance of the software. For questions regarding the organisation of your Foodcoop, please contact the appropriate contact person. + send: Send + title: Give feedback finance: balancing: close: @@ -1137,6 +1190,11 @@ en: tasks: required_users: "%{count} members are still needed!" task_title: "%{name} (%{duration}h)" + unit_conversion_fields: + title: Convert units + disabled_title: Unit cannot be converted + cancel: Cancel + apply: Apply home: apple_bar: desc: 'This shows the proportion of completed tasks to the volume of orders for your ordergroup in comparison to the average of the Foodcoop. In practice: for every %{amount} of total orders, you should execute a task!' @@ -1427,6 +1485,7 @@ en: stock: Stock suppliers: Suppliers/articles title: Articles + article_units: Article units dashboard: Dashboard finances: accounts: Manage accounts @@ -1488,6 +1547,7 @@ en: heading: Order for %{name} name: Name number: Number + unit: Unit to_address: Shipping address finish: notice: The order has been closed. @@ -1605,6 +1665,15 @@ en: ordered_desc: Number of articles as ordered by member (amount + tolerance) received: Received received_desc: Number of articles that (will be) received by member + article_fields_units: + custom_unit: Custom + unit: Unit + unit_ratios: Unit ratios + add_ratio: Add ratio + warn_about_needless_custom_unit: Refrain from using custom plain text units when there are apt units in the dropdown. (Choosing units from the dropdown allows for interoperability with other systems and enables automatically converting them into other units.) + article_unit_ratio: + remove: Remove ratio + per: per articles_by: price: Total price price_sum: Sum @@ -1769,6 +1838,21 @@ en: stock_changes: Stock quantity changes update: notice: Stock article %{name} was saved. + article_units: + index: + search: Search for unit/symbol + only_recommended: Only recommended + rows: + request_translation: There is no translation available for this unit. If you think this unit might be of common use, click here to create a new GitHub issue. + create_link: + add: Add + destroy_link: + delete: Remove + confirm: Do you really want to remove this article unit? (Existing articles using this unit will not be altered, but it won't be possible to use it for new articles.) + create: + success: Article unit %{name} has been added successfully. + destroy: + success: Article unit %{name} has been removed successfully. suppliers: create: notice: Supplier was created @@ -1802,8 +1886,19 @@ en: last_orders: Last orders new_delivery: New delivery show_deliveries: Show all + share: Share + remove_share: Remove share + confirm_remove_share: Do you really want to stop sharing this supplier's articles? (If you later decide to start sharing them again, you'll have to resend the new link to all subscribers who you think should have access.) update: notice: Supplier was updated + import_search_results: + action_import: import + already_imported: imported + not_found: No articles found + supplier_shares: + share_link: + not_shared: Supplier's articles are currently not shared with anyone. + share_link_copied_to_clipboard: Share link has been copied to the clipboard. tasks: accept: notice: You have accepted the task diff --git a/config/locales/es.yml b/config/locales/es.yml index f9e117722..6ca9819ce 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -28,7 +28,7 @@ es: article_category: description: Importar nombres name: Nombre - article_price: + article_version: deposit: Depósito price: Precio (neto) tax: IVA @@ -239,7 +239,7 @@ es: errors: has_many_left: todavía está asociado con un %{collection}! models: - article: + article_version: attributes: name: taken: ese nombre ya está cogido @@ -481,14 +481,10 @@ es: notice: "Se han guardado %{count} nuevos artículos." error_invalid: Hay errores en los artículos error_nosel: No se ha seleccionado ningún artículo - error_parse: "%{msg} ... en la línea %{line}" error_update: 'Ha ocurrido un error miebtras se actualizaba el artículo ''%{article}'': %{msg}' parse_upload: no_file: Elige un archivo para subir. notice: "%{count} artículos fueron analizados con éxito." - sync: - notice: El catálogo está actualizado - shared_alert: "%{supplier} no está conectado a una base de datos externa" update_all: notice: Se han actualizado todos los artículos y precios. update_sel: @@ -509,10 +505,6 @@ es: form: title_edit: Editar artículo title_new: Añadir un nuevo artículo - import_search_results: - action_import: importar - already_imported: importado - not_found: No se han encontrado articulos index: change_supplier: Cambiar proveedor download: Descargar artículos @@ -758,9 +750,8 @@ es: rows: - Número de pedido - Importe - - Nombre - - Cantidad de unidades - Unidad + - Nombre - Precio/Unidad - Subtotal total: Total @@ -1795,6 +1786,10 @@ es: show_deliveries: Muestra todos update: notice: Se ha actualizado el proveedor/a + import_search_results: + action_import: importar + already_imported: importado + not_found: No se han encontrado articulos tasks: accept: notice: Has aceptado la tarea diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 83226eb07..4b996cb01 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -27,7 +27,7 @@ fr: article_category: description: Description name: Nom - article_price: + article_version: deposit: Consigne price: Prix HT tax: TVA @@ -315,13 +315,9 @@ fr: notice: "%{count} nouveaux produits on été sauvegardés." error_invalid: La description des produits comporte des erreurs. error_nosel: Aucun produit n'a été sélectionné - error_parse: "%{msg} ... à la ligne %{line}" error_update: 'Une erreur s''est produite lors de la mise à jour du produit "%{article}": %{msg}' parse_upload: notice: "%{count} produits ont été examinés avec succès." - sync: - notice: Le catalogue est à jour - shared_alert: "%{supplier} n'est pas dans l'annuaire mutualisé." update_all: notice: Les produits et les prix ont été mis à jour. update_sel: @@ -342,10 +338,6 @@ fr: form: title_edit: Modifier ce produit title_new: Ajouter un nouveau produit - import_search_results: - action_import: importer - already_imported: déjà importé - not_found: Aucun produit correspondant n'a été trouvé index: change_supplier: Changer de fournisseur-e edit_all: Tout modifier @@ -480,9 +472,8 @@ fr: rows: - Numéro - Quantité - - Nom du produit - - Nombre d'unités - Unité + - Nom du produit - Prix unitaire - Prix order_matrix: @@ -1288,6 +1279,10 @@ fr: show_deliveries: Afficher tous les réapprovisionnements update: notice: Les données du-de la fournisseur-e ont été mises à jour + import_search_results: + action_import: importer + already_imported: déjà importé + not_found: Aucun produit correspondant n'a été trouvé tasks: accept: notice: Tu as accepté ce boulot diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 6bcb06c69..45be988e0 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -28,7 +28,7 @@ nl: article_category: description: Namen importeren name: Naam - article_price: + article_version: deposit: Statiegeld price: Nettoprijs tax: BTW @@ -239,7 +239,7 @@ nl: errors: has_many_left: is nog met een %{collection} verbonden! models: - article: + article_version: attributes: name: taken: naam bestaat al @@ -481,14 +481,10 @@ nl: notice: "Er zijn %{count} nieuwe artikelen opgeslagen." error_invalid: Er zijn artikelen die een fout hebben error_nosel: Geen artikelen geselecteerd - error_parse: "%{msg} … in regel %{line}" error_update: 'Er trad een fout op bij het bijwerken van artikel ''%{article}'': %{msg}' parse_upload: no_file: Een bestand om te uploaden kiezen. notice: "%{count} artikelen zijn geanalyseerd" - sync: - notice: Catalogus is bijgewerkt - shared_alert: "%{supplier} is niet aan een externe database gekoppeld" update_all: notice: Alle artikelen en prijzen zijn bijgewerkt. update_sel: @@ -509,10 +505,6 @@ nl: form: title_edit: Artikel bewerken title_new: Nieuw artikel toevoegen - import_search_results: - action_import: importeren - already_imported: geïmporteerd - not_found: Geen artikelen gevonden index: change_supplier: Leverancier wisselen download: Artikelen downloaden @@ -758,9 +750,8 @@ nl: rows: - Nummer - Aantal - - Naam - - Colli - Eenheid + - Naam - Prijs/eenh. - Subtotaal total: Totaal @@ -1790,6 +1781,10 @@ nl: show_deliveries: Alle leveringen tonen update: notice: Leverancier is bijgewerkt + import_search_results: + action_import: importeren + already_imported: geïmporteerd + not_found: Geen artikelen gevonden tasks: accept: notice: Je hebt de taak geaccepteerd diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 3f26a56b6..4f670353c 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -163,7 +163,7 @@ tr: last_order: Son sipariş last_user_activity: Son etkinlik name: Adı - user_tokens: Üyeler + user_tokens: Üyeler stock_article: available: Mevcut price: Fiyat @@ -239,7 +239,7 @@ tr: errors: has_many_left: Bu %{collection} ile hala ilişkili! models: - article: + article_version: attributes: name: taken: isim zaten alınmış @@ -481,14 +481,10 @@ tr: notice: "%{count} yeni ürün kaydedildi." error_invalid: Ürünlerde hatalar var error_nosel: Seçilmiş bir ürün yok - error_parse: "%{msg} ... satır %{line}'da" error_update: '%{article} ürünleri güncellerken bir hata oluştu: %{msg}' parse_upload: no_file: Lütfen yüklemek için bir dosya seçin. notice: "%{count} ürün başarıyla analiz edildi." - sync: - notice: Katalog güncel - shared_alert: "%{supplier} harici bir veritabanına bağlı değil" update_all: notice: Tüm ürünler ve fiyatlar güncellendi. update_sel: @@ -509,10 +505,6 @@ tr: form: title_edit: Ürün düzenle title_new: Yeni ürün ekle - import_search_results: - action_import: İçe aktar - already_imported: içe aktarıldı - not_found: Ürün bulunamadı index: change_supplier: Tedarikçi değiştir download: Ürünleri indir @@ -757,9 +749,8 @@ tr: rows: - Sipariş Numarası - Miktar - - Ad - - Birim miktarı - Birim + - Ad - Birim fiyatı - Ara toplam total: Toplam @@ -1026,7 +1017,7 @@ tr: group_order_articles: form: amount_change_for: '%{article} için miktarı değiştirin' - result_hint: 'Birim: %{unit}' + result_hint: 'Birim: %{unit}' group_orders: archive: desc: Tüm %{link} burada görüntüleyebilirsiniz. @@ -1099,7 +1090,7 @@ tr: update: error_general: Sipariş bir hatadan dolayı güncellenemedi. error_stale: Bu sırada başka birisi sipariş vermiş, sipariş güncellenemedi. - notice: Sipariş kaydedildi. + notice: Sipariş kaydedildi. helpers: application: edit_user: Kullanıcıyı düzenle @@ -1288,7 +1279,7 @@ tr: text: | Sevgili %{user}, - Çalışma grubunun '%{task}' görevi %{when} tarihinde tamamlanacak + Çalışma grubunun '%{task}' görevi %{when} tarihinde tamamlanacak ve daha fazla katılımcıya ihtiyaç duyuyor! Eğer henüz bu göreve atanmadıysanız, şimdi fırsatınız var: @@ -1342,9 +1333,9 @@ tr: text: | Merhaba %{user}, - Yeni bir şifre istediniz (veya başka birisi istedi). + Yeni bir şifre istediniz (veya başka birisi istedi). Yeni bir şifre belirlemek için bu linke tıklayın: %{link} - Bu link sadece bir kez kullanılabilir ve %{expires} tarihinde geçersiz olacaktır. + Bu link sadece bir kez kullanılabilir ve %{expires} tarihinde geçersiz olacaktır. Eğer şifrenizi değiştirmek istemiyorsanız, bu mesajı görmezden gelebilirsiniz. Şifreniz henüz değiştirilmedi. @@ -1434,7 +1425,7 @@ tr: pickups: Teslim Günleri title: Siparişler tasks: Görevler - workgroups: Çalışma Grupları + workgroups: Çalışma Grupları number: percentage: format: @@ -1793,6 +1784,10 @@ tr: show_deliveries: Tümünü göster update: notice: Tedarikçi güncellendi + import_search_results: + action_import: İçe aktar + already_imported: içe aktarıldı + not_found: Ürün bulunamadı tasks: accept: notice: Görevi kabul ettiniz diff --git a/config/navigation.rb b/config/navigation.rb index 360f831ca..6e5d99e0c 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -24,9 +24,7 @@ subnav.item :ordering, I18n.t('navigation.orders.ordering'), group_orders_path subnav.item :ordering_archive, I18n.t('navigation.orders.archive'), archive_group_orders_path subnav.item :orders, I18n.t('navigation.orders.manage'), orders_path, if: proc { current_user.role_orders? } - subnav.item :pickups, I18n.t('navigation.orders.pickups'), pickups_path, if: proc { - current_user.role_pickups? - } + subnav.item :pickups, I18n.t('navigation.orders.pickups'), pickups_path, if: proc { current_user.role_pickups? } end primary.item :articles, I18n.t('navigation.articles.title'), '#', @@ -34,6 +32,7 @@ subnav.item :suppliers, I18n.t('navigation.articles.suppliers'), suppliers_path subnav.item :stockit, I18n.t('navigation.articles.stock'), stock_articles_path subnav.item :categories, I18n.t('navigation.articles.categories'), article_categories_path + subnav.item :article_units, I18n.t('navigation.articles.article_units'), article_units_path end primary.item :finance, I18n.t('navigation.finances.title'), '#', if: proc { diff --git a/config/puma.rb b/config/puma.rb index 609df0adc..1cf9d2d6e 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -56,3 +56,6 @@ # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart + +# TODO: Check if we can leave that in there - see https://github.com/foodcoopsat/foodsoft_hackathon/issues/95: +worker_timeout 3600 if ENV.fetch('RAILS_ENV') == 'development' diff --git a/config/routes.rb b/config/routes.rb index 9ce1284a4..e93f642ff 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -114,8 +114,15 @@ end end + resources :article_units do + collection do + get :search + end + end + resources :suppliers do - get :shared_suppliers, on: :collection + get :remote_articles + resource :share, only: %i[create destroy], controller: :supplier_shares resources :deliveries do collection do @@ -131,12 +138,13 @@ collection do post :update_selected get :edit_all + get :prepare_units_migration + get :migrate_units + post :complete_units_migration post :update_all get :upload post :parse_upload post :create_from_upload - get :shared - get :import post :sync post :update_synchronized end @@ -285,6 +293,10 @@ resources :order_articles, only: %i[index show] resources :group_order_articles resources :article_categories, only: %i[index show] + + resources :shared_suppliers, param: :uuid, only: [] do + resources :articles, only: [:index] + end end end @@ -293,4 +305,3 @@ resources :users, only: [:index] end # End of /:foodcoop scope end -# rubocop:enable Metrics/BlockLength diff --git a/config/units-of-measure/locales/unece_de.yml b/config/units-of-measure/locales/unece_de.yml new file mode 100644 index 000000000..2719abfbf --- /dev/null +++ b/config/units-of-measure/locales/unece_de.yml @@ -0,0 +1,763 @@ +# This file has been autogenerated by `rake units:build_i18n_from_csv` +--- +unece_units: + XCU: + name: Becher + XCN: + name: Behälter + XSH: + name: Beutel + X43: + name: Bigbag + XST: + name: Blatt + abbreviation: Bl. + XOK: + name: Block + XVA: + name: Bottich + XBX: + name: Box + XBH: + name: Bund + abbreviation: Bd. + aliases: + - bd + XBE: + name: Bündel + abbreviation: Bdl. + XCX: + name: Dose + XBJ: + name: Eimer + XUN: + name: Einheit + XOS: + name: Einweg-Palette + XDH: + name: Eurobox, CHEP-Box + abbreviation: Box + XBA: + name: Fass + XFI: + name: Fässchen + XBO: + name: Flasche + abbreviation: Fl. + aliases: + - fl + XBQ: + name: Flasche in Umverpackung + abbreviation: Fl. + XFB: + name: Flexibag + XFT: + name: Foodtainer + XJR: + name: Glas + abbreviation: Gl. + aliases: + - gl + XGR: + name: Glasgefäß + XOW: + name: Großer Sack in Palettengröße + X8B: + name: Holzkiste + XCV: + name: Hülle + XWA: + name: Intermediate Bulk Container (IBC) + abbreviation: IBC + XEI: + name: Isotherme Box + XJT: + name: Jutebeutel + XGY: + name: Jutesack + XJY: + name: Kanister + XBD: + name: Karton + XCR: + name: Kiste + XAI: + name: Klappverpackung + XPA: + name: Kollo + XBK: + name: Korb + XBI: + name: Kübel + XOV: + name: Mehrwegpalette + XNT: + name: Netz + XPK: + name: Packung + abbreviation: Pkg. + aliases: + - pkg + - pkt + XPC: + name: Paket + XPX: + name: Palette + X5M: + name: Papiertüte + XPR: + name: Plastikgefäß + XEC: + name: Plastiktüte + X6H: + name: Plastik-Verbundverpackung + X44: + name: Polybeutel + XBR: + name: Riegel + XCW: + name: Rollcontainer + XBT: + name: Rolle + XSA: + name: Sack + XBM: + name: Schüssel + XSX: + name: Set + XDN: + name: Spender + XAE: + name: Sprühdose + XSC: + name: Steige + XLU: + name: Stiege + X5L: + name: Stofftüte + XPP: + name: Stück + aliases: + - stk + - st + - stueck + XPU: + name: Schale + XBG: + name: Tasche + XP2: + name: Tiegel + XCK: + name: Tonne + XPT: + name: Topf + aliases: + - tiegel + XGI: + name: Träger + XTU: + name: Tube + PTN: + name: Portion + long_name: Portion + symbols: [] + STC: + name: Stange + long_name: Stange + symbols: [] + DMT: + name: Dezimeter + long_name: Dezimeter + symbols: + - dm + CMT: + name: Zentimeter + long_name: Zentimeter + symbols: + - cm + 4H: + name: Mikrometer + long_name: Mikrometer (Mikron) + symbols: + - µm + MMT: + name: Millimeter + long_name: Millimeter + symbols: + - mm + HMT: + name: Hektometer + long_name: Hektometer + symbols: + - hm + KMT: + name: Kilometer + long_name: Kilometer + symbols: + - km + A45: + name: Dekameter + long_name: Dekameter + symbols: + - dam + INH: + name: Zoll + long_name: Zoll + symbols: + - "″" + - in + FOT: + name: Fuß + long_name: Fuß + symbols: + - ft + YRD: + name: Yard + long_name: Yard + symbols: + - yd + SMI: + name: Meile + long_name: Meile (britisch) + symbols: + - mile + '77': + name: Millizoll + long_name: Millizoll + symbols: + - mil + MTK: + name: Quadratmeter + long_name: Quadratmeter + symbols: + - m² + - qm + DAA: + name: Dekar + long_name: Dekar + symbols: + - daa + KMK: + name: Quadratkilometer + long_name: Quadratkilometer + symbols: + - km² + CMK: + name: Quadratzentimeter + long_name: Quadratzentimeter + symbols: + - cm² + DMK: + name: Quadratdezimeter + long_name: Quadratdezimeter + symbols: + - dm² + H16: + name: Quadratdekameter + long_name: Quadratdekameter + symbols: + - dam² + H18: + name: Quadrathektometer + long_name: Quadrathektometer + symbols: + - hm² + MMK: + name: Quadratmillimeter + long_name: Quadratmillimeter + symbols: + - mm² + M47: + name: Circular mil + long_name: Circular mil + symbols: + - cmil + ARE: + name: Ar + long_name: Ar + symbols: + - a + HAR: + name: Hektar + long_name: Hektar + symbols: + - ha + INK: + name: Quadratzoll + long_name: Quadratzoll + symbols: + - in² + FTK: + name: Quadratfuß + long_name: Quadratfuß + symbols: + - ft² + YDK: + name: Quadratmeter + long_name: Quadratmeter + symbols: + - yd² + MIK: + name: Quadratmeile + long_name: Quadratmeile (britisch) + symbols: + - mi² + ACR: + name: Morgen + long_name: Morgen + symbols: + - acre + KGM: + name: Kilogramm + long_name: Kilogramm + symbols: + - kg + aliases: + - kilo + HGM: + name: Hektogramm + long_name: Hektogramm + symbols: + - hg + KTN: + name: Kilotonne + long_name: Kilotonne + symbols: + - kt + DJ: + name: Dekagramm + long_name: Dekagramm + symbols: + - dag + - dkg + DG: + name: Dezigramm + long_name: Dezigramm + symbols: + - dg + CGM: + name: Zentigramm + long_name: Zentigramm + symbols: + - cg + DTN: + name: Dezitonne + long_name: Dezitonne + symbols: + - dt + - dtn + MGM: + name: Milligramm + long_name: Milligramm + symbols: + - mg + 2U: + name: Megagramm + long_name: Megagramm + symbols: + - Mg + MC: + name: Mikrogramm + long_name: Mikrogramm + symbols: + - µg + GRM: + name: Gramm + long_name: Gramm + symbols: + - g + aliases: + - gr + - grm + TNE: + name: Tonne + long_name: Tonne (metrisch) + symbols: + - t + M86: + name: Pfund + long_name: Pfund + symbols: + - pfd + LBR: + name: Englisches Pfund + long_name: Englisches Pfund + symbols: + - lb + GRN: + name: Gran + long_name: Gran + symbols: + - gr + ONZ: + name: Unze + long_name: Unze (avoirdupois) + symbols: + - oz + CWI: + name: Br. Zentner + long_name: Hundredweight (britisch) + symbols: + - cwt + CWA: + name: Am. Zentner + long_name: Hundredweight (amerikanisch) + symbols: + - cwt + LTN: + name: Br. Tonne + long_name: Britische Tonne, Long Ton (amerikanisch) + symbols: + - ton (Br.) + STI: + name: Stein + long_name: Stein (britisch) + symbols: + - st + STN: + name: Am. Tonne + long_name: Amerikanische Tonne, Short Ton + symbols: + - ton (Am.) + APZ: + name: Feinunze + long_name: Feinunze oder Apothekerunze + symbols: + - tr oz + F13: + name: Slug + long_name: Slug + symbols: + - slug + SEC: + name: Sekunde + long_name: Sekunde [Zeiteinheit] + symbols: + - s + MIN: + name: Minute + long_name: Minute [Zeiteinheit] + symbols: + - min + HUR: + name: Stunde + long_name: Stunde + symbols: + - h + DAY: + name: Tag + long_name: Tag + symbols: + - d + C26: + name: Millisekunde + long_name: Millisekunde + symbols: + - ms + WEE: + name: Woche + long_name: Woche + symbols: + - wk + MON: + name: Monat + long_name: Monat + symbols: + - mo + ANN: + name: Jahr + long_name: Jahr + symbols: + - y + MTQ: + name: Kubikmeter + long_name: Kubikmeter + symbols: + - m³ + - cbm + LTR: + name: Liter + long_name: Liter + symbols: + - l + MAL: + name: Megaliter + long_name: Megaliter + symbols: + - Ml + DLT: + name: Deziliter + long_name: Deziliter + symbols: + - dl + 4G: + name: Mikroliter + long_name: Mikroliter + symbols: + - µl + K6: + name: Kiloliter + long_name: Kiloliter + symbols: + - kl + A44: + name: Dekaliter + long_name: Dekaliter + symbols: + - dal + MMQ: + name: Kubikmillimeter + long_name: Kubikmillimeter + symbols: + - mm³ + CMQ: + name: Kubikzentimeter + long_name: Kubikzentimeter + symbols: + - cm³ + - ccm + DMQ: + name: Kubikdezimeter + long_name: Kubikdezimeter + symbols: + - dm³ + MLT: + name: Milliliter + long_name: Milliliter + symbols: + - ml + HLT: + name: Hektoliter + long_name: Hektoliter + symbols: + - hl + CLT: + name: Zentiliter + long_name: Zentiliter + symbols: + - cl + DMA: + name: Kubikdekameter + long_name: Kubikdekameter + symbols: + - dam³ + H19: + name: Kubikhektometer + long_name: Kubikhektometer + symbols: + - hm³ + H20: + name: Kubikkilometer + long_name: Kubikkilometer + symbols: + - km³ + M67: + name: acre-foot + long_name: acre-foot (basierend auf U.S. Survey Foot) + symbols: + - acre-ft + M68: + name: Cord + long_name: Cord (128 ft3) + symbols: + - cord + M69: + name: Kubikmeile + long_name: Kubikmeile (britisch) + symbols: + - mi³ + M70: + name: Registertonne + long_name: Registertonne + symbols: + - RT + 5I: + name: Kubikfuß + long_name: Kubikfuß + symbols: + - std + INQ: + name: Kubikzoll + long_name: Kubikzoll + symbols: + - in³ + FTQ: + name: Kubikfuß + long_name: Kubikfuß + symbols: + - ft³ + YDQ: + name: Kubikmeter + long_name: Kubikmeter + symbols: + - yd³ + GLI: + name: Gallone (Br.) + long_name: Gallone (britisch) + symbols: + - gal + GLL: + name: Gallone (Am.) + long_name: Gallone (amerikanisch) + symbols: + - gal + PTI: + name: Pint (Br.) + long_name: Pint (britisch) + symbols: + - pt + QTI: + name: Quart + long_name: quart (britisch) + symbols: + - qt + PTL: + name: flüssiges Pint (Am.) + long_name: flüssiges Pint (amerikanisch) + symbols: + - liq pt + QTL: + name: flüssiges Quart (Am.) + long_name: flüssiges Quart (amerikanisch) + symbols: + - liq qt + PTD: + name: trockenes Pint (Am.) + long_name: trockenes Pint (amerikanisch) + symbols: + - dry pt + OZI: + name: flüssige Unze (Br.) + long_name: flüssige Unze (britisch) + symbols: + - fl oz + J57: + name: Barrel (Br.) + long_name: Barrel (britisch) + symbols: + - bbl + L43: + name: Viertelscheffel (Br.) + long_name: peck (britisch) + symbols: + - pk + L84: + name: Shipping ton (Br.) + long_name: ton (UK shipping) + symbols: + - Shipping ton (Br.) + L86: + name: Shipping ton (Am.) + long_name: ton (US shipping) + symbols: + - Shipping ton (Am.) + OZA: + name: Flüssigunze + long_name: Flüssigunze (amerikanisch) + symbols: + - fl oz + BUI: + name: Scheffel (Br.) + long_name: Scheffel (britisch) + symbols: + - bushel + BUA: + name: Scheffel (Am.) + long_name: Scheffel (amerikanisch) + symbols: + - bu + BLL: + name: Barrel (Am.) + long_name: Barrel (amerikanisch) + symbols: + - barrel + BLD: + name: Dry Barrel (Am.) + long_name: Dry Barrel (amerikanisch) + symbols: + - bbl + GLD: + name: Dry Gallon (Am.) + long_name: Dry Gallon (amerikanisch) + symbols: + - dry gal + QTD: + name: Dry Quart (Am.) + long_name: Dry Quart (amerikanisch) + symbols: + - dry qt + G26: + name: Ster + long_name: Ster (Schüttraummeter) + symbols: + - st + G21: + name: Tasse + long_name: Tasse [Volumeneinheit] + symbols: + - cup + G24: + name: Esslöffel + long_name: Esslöffel + symbols: + - EL + G25: + name: Teelöffel + long_name: Teelöffel + symbols: + - TL + G23: + name: Viertelscheffel (Am.) + long_name: Viertelscheffel (amerikanisch) + symbols: + - pk + JOU: + name: Joule + long_name: Joule + symbols: + - J + J75: + name: Kalorie + long_name: Kalorie + symbols: + - cal + K51: + name: Kilokalorie + long_name: Kilokalorie + symbols: + - kcal + J55: + name: Wattsekunde + long_name: Wattsekunde + symbols: + - Ws + WHR: + name: Wattstunde + long_name: Wattstunde + symbols: + - Wh + KWH: + name: Kilowattstunde + long_name: Kilowattstunde + symbols: + - kWh + GWH: + name: Gigawattstunde + long_name: Gigawattstunde + symbols: + - GWh + WTT: + name: Watt + long_name: Watt + symbols: + - W + KWT: + name: Kilowatt + long_name: Kilowatt + symbols: + - kW + MAW: + name: Megawatt + long_name: Megawatt + symbols: + - MW diff --git a/config/units-of-measure/locales/unece_en.yml b/config/units-of-measure/locales/unece_en.yml new file mode 100644 index 000000000..f6eb87300 --- /dev/null +++ b/config/units-of-measure/locales/unece_en.yml @@ -0,0 +1,761 @@ +# This file has been autogenerated by `rake units:build_i18n_from_csv` +--- +unece_units: + XCU: + name: Cup + XCN: + name: Container + XSH: + name: Sachet + X43: + name: Big bag + XST: + name: Sheet + XOK: + name: Block + XVA: + name: Vat + XBX: + name: Box + XBH: + name: Bunch + XBE: + name: Bundle + abbreviation: bdl. + XCX: + name: Can + XBJ: + name: Bucket + XUN: + name: Unit + XOS: + name: Oneway pallet + XDH: + name: Eurobox, CHEP box + abbreviation: box + XBA: + name: Barrel + XFI: + name: Firkin + XBO: + name: Bottle + abbreviation: btl. + aliases: + - btl + XBQ: + name: Protected bottle + abbreviation: btl. + XFB: + name: Flexibag + XFT: + name: Foodtainer + XJR: + name: Jar + XGR: + name: Glass receptacle + XOW: + name: Pallet sized large bag + X8B: + name: Wooden crate + XCV: + name: Cover + XWA: + name: Intermediate bulk container (IBC) + abbreviation: IBC + XEI: + name: Isothermic case + XJT: + name: Jutebag + XGY: + name: Gunny bag + XJY: + name: Jerrican + XBD: + name: Board + XCR: + name: Crate + XAI: + name: Clamshell + XPA: + name: Packet + XBK: + name: Basket + XBI: + name: Bin + XOV: + name: Returnable pallet + XNT: + name: Net + XPK: + name: Package + abbreviation: pkg. + aliases: + - pkg + XPC: + name: Parcel + XPX: + name: Pallet + X5M: + name: Paper bag + XPR: + name: Plastic receptacle + XEC: + name: Plastic bag + X6H: + name: Plastic composite packaging + X44: + name: Polybag + XBR: + name: Bar + XCW: + name: Roll cage + XBT: + name: Bolt + XSA: + name: Sack + XBM: + name: Bowl + XSX: + name: Set + XDN: + name: Dispenser + XAE: + name: Aerosol + XSC: + name: Shallow crate + XLU: + name: Lug + X5L: + name: Textile bag + XPP: + name: Piece + aliases: + - pc + XPU: + name: Tray + XBG: + name: Bag + XP2: + name: Pan + XCK: + name: Cask + XPT: + name: Pot + XGI: + name: Girder + XTU: + name: Tube + PTN: + name: portion + long_name: portion + symbols: [] + STC: + name: stick + long_name: stick + symbols: [] + DMT: + name: decimetre + long_name: decimetre + symbols: + - dm + CMT: + name: centimetre + long_name: centimetre + symbols: + - cm + 4H: + name: micrometre + long_name: micrometre (micron) + symbols: + - µm + MMT: + name: millimetre + long_name: millimetre + symbols: + - mm + HMT: + name: hectometre + long_name: hectometre + symbols: + - hm + KMT: + name: kilometre + long_name: kilometre + symbols: + - km + A45: + name: decametre + long_name: decametre + symbols: + - dam + INH: + name: inch + long_name: inch + symbols: + - in + FOT: + name: foot + long_name: foot + symbols: + - ft + YRD: + name: yard + long_name: yard + symbols: + - yd + SMI: + name: mile + long_name: mile (statute mile) + symbols: + - mile + '77': + name: milli-inch + long_name: milli-inch + symbols: + - mil + MTK: + name: square metre + long_name: square metre + symbols: + - m² + - sq m + DAA: + name: decare + long_name: decare + symbols: + - daa + KMK: + name: square kilometre + long_name: square kilometre + symbols: + - km² + - sq km + CMK: + name: square centimetre + long_name: square centimetre + symbols: + - cm² + - sq cm + DMK: + name: square decimetre + long_name: square decimetre + symbols: + - dm² + - sq dm + H16: + name: square decametre + long_name: square decametre + symbols: + - dam² + - sq dam + H18: + name: square hectometre + long_name: square hectometre + symbols: + - hm² + - sq hm + MMK: + name: square millimetre + long_name: square millimetre + symbols: + - mm² + - sq mm + M47: + name: circular mil + long_name: circular mil + symbols: + - cmil + ARE: + name: are + long_name: are + symbols: + - a + HAR: + name: hectare + long_name: hectare + symbols: + - ha + INK: + name: square inch + long_name: square inch + symbols: + - in² + - sq in + FTK: + name: square foot + long_name: square foot + symbols: + - ft² + - sq ft + YDK: + name: square yard + long_name: square yard + symbols: + - yd² + - sq yd + MIK: + name: square mile + long_name: square mile (statute mile) + symbols: + - mi² + - sq mi + ACR: + name: acre + long_name: acre + symbols: + - acre + KGM: + name: kilogram + long_name: kilogram + symbols: + - kg + aliases: + - kilo + HGM: + name: hectogram + long_name: hectogram + symbols: + - hg + KTN: + name: kilotonne + long_name: kilotonne + symbols: + - kt + DJ: + name: decagram + long_name: decagram + symbols: + - dag + - dkg + DG: + name: decigram + long_name: decigram + symbols: + - dg + CGM: + name: centigram + long_name: centigram + symbols: + - cg + DTN: + name: decitonne + long_name: decitonne + symbols: + - dt + - dtn + MGM: + name: milligram + long_name: milligram + symbols: + - mg + 2U: + name: megagram + long_name: megagram + symbols: + - Mg + MC: + name: microgram + long_name: microgram + symbols: + - µg + GRM: + name: gram + long_name: gram + symbols: + - g + aliases: + - gr + - grm + TNE: + name: metric ton + long_name: tonne (metric) + symbols: + - t + - mt + M86: + name: pfund + long_name: pfund + symbols: + - pfd + LBR: + name: pound + long_name: pound + symbols: + - lb + GRN: + name: grain + long_name: grain + symbols: + - gr + ONZ: + name: ounce + long_name: ounce (avoirdupois) + symbols: + - oz + CWI: + name: hundred weight + long_name: hundred weight (UK) + symbols: + - cwt + CWA: + name: hundred pound (cwt) / hundred weight (US) + long_name: hundred pound (cwt) / hundred weight (US) + symbols: + - cwt + LTN: + name: ton (UK) or long ton (US) + long_name: ton (UK) or long ton (US) + symbols: + - ton (UK) + STI: + name: stone + long_name: stone (UK) + symbols: + - st + STN: + name: ton (US) or short ton (UK/US) + long_name: ton (US) or short ton (UK/US) + symbols: + - ton (US) + APZ: + name: troy ounce + long_name: troy ounce or apothecary ounce + symbols: + - tr oz + F13: + name: slug + long_name: slug + symbols: + - slug + SEC: + name: second + long_name: second [unit of time] + symbols: + - s + MIN: + name: minute + long_name: minute [unit of time] + symbols: + - min + HUR: + name: hour + long_name: hour + symbols: + - h + DAY: + name: day + long_name: day + symbols: + - d + C26: + name: millisecond + long_name: millisecond + symbols: + - ms + WEE: + name: week + long_name: week + symbols: + - wk + MON: + name: month + long_name: month + symbols: + - mo + ANN: + name: year + long_name: year + symbols: + - y + MTQ: + name: cubic metre + long_name: cubic metre + symbols: + - m³ + LTR: + name: litre + long_name: litre + symbols: + - l + MAL: + name: megalitre + long_name: megalitre + symbols: + - Ml + DLT: + name: decilitre + long_name: decilitre + symbols: + - dl + 4G: + name: microlitre + long_name: microlitre + symbols: + - µl + K6: + name: kilolitre + long_name: kilolitre + symbols: + - kl + A44: + name: decalitre + long_name: decalitre + symbols: + - dal + MMQ: + name: cubic millimetre + long_name: cubic millimetre + symbols: + - mm³ + CMQ: + name: cubic centimetre + long_name: cubic centimetre + symbols: + - cm³ + - cc + - ccm + DMQ: + name: cubic decimetre + long_name: cubic decimetre + symbols: + - dm³ + MLT: + name: millilitre + long_name: millilitre + symbols: + - ml + HLT: + name: hectolitre + long_name: hectolitre + symbols: + - hl + CLT: + name: centilitre + long_name: centilitre + symbols: + - cl + DMA: + name: cubic decametre + long_name: cubic decametre + symbols: + - dam³ + H19: + name: cubic hectometre + long_name: cubic hectometre + symbols: + - hm³ + H20: + name: cubic kilometre + long_name: cubic kilometre + symbols: + - km³ + M67: + name: acre-foot + long_name: acre-foot (based on U.S. survey foot) + symbols: + - acre-ft + M68: + name: cord + long_name: cord (128 ft3) + symbols: + - cord + M69: + name: cubic mile + long_name: cubic mile (UK statute) + symbols: + - mi³ + M70: + name: register ton + long_name: register ton + symbols: + - RT + 5I: + name: standard cubic foot + long_name: standard cubic foot + symbols: + - std + INQ: + name: cubic inch + long_name: cubic inch + symbols: + - in³ + FTQ: + name: cubic foot + long_name: cubic foot + symbols: + - ft³ + YDQ: + name: cubic yard + long_name: cubic yard + symbols: + - yd³ + GLI: + name: gallon (UK) + long_name: gallon (UK) + symbols: + - gal + GLL: + name: gallon (US) + long_name: gallon (US) + symbols: + - gal + PTI: + name: pint (UK) + long_name: pint (UK) + symbols: + - pt + QTI: + name: quart (UK) + long_name: quart (UK) + symbols: + - qt + PTL: + name: liquid pint (US) + long_name: liquid pint (US) + symbols: + - liq pt + QTL: + name: liquid quart (US) + long_name: liquid quart (US) + symbols: + - liq qt + PTD: + name: dry pint (US) + long_name: dry pint (US) + symbols: + - dry pt + OZI: + name: fluid ounce (UK) + long_name: fluid ounce (UK) + symbols: + - fl oz + J57: + name: barrel (UK petroleum) + long_name: barrel (UK petroleum) + symbols: + - bbl + L43: + name: peck (UK) + long_name: peck (UK) + symbols: + - pk (UK) + L84: + name: ton (UK shipping) + long_name: ton (UK shipping) + symbols: + - British shipping ton + L86: + name: ton (US shipping) + long_name: ton (US shipping) + symbols: + - "(US) shipping ton" + OZA: + name: fluid ounce (US) + long_name: fluid ounce (US) + symbols: + - fl oz + BUI: + name: bushel (UK) + long_name: bushel (UK) + symbols: + - bushel + BUA: + name: bushel (US) + long_name: bushel (US) + symbols: + - bu + BLL: + name: barrel (US) + long_name: barrel (US) + symbols: + - barrel + BLD: + name: dry barrel (US) + long_name: dry barrel (US) + symbols: + - bbl + GLD: + name: dry gallon (US) + long_name: dry gallon (US) + symbols: + - dry gal + QTD: + name: dry quart (US) + long_name: dry quart (US) + symbols: + - dry qt + G26: + name: stere + long_name: stere + symbols: + - st + G21: + name: cup + long_name: cup [unit of volume] + symbols: + - cup + G24: + name: tablespoon + long_name: tablespoon (US) + symbols: + - tbsp. + G25: + name: teaspoon + long_name: teaspoon (US) + symbols: + - tsp. + G23: + name: peck (US) + long_name: peck (US) + symbols: + - pk (US) + JOU: + name: joule + long_name: joule + symbols: + - J + J75: + name: calorie + long_name: calorie (mean) + symbols: + - cal + K51: + name: kilocalorie + long_name: kilocalorie (mean) + symbols: + - kcal + J55: + name: watt second + long_name: watt second + symbols: + - Ws + WHR: + name: watt hour + long_name: watt hour + symbols: + - Wh + KWH: + name: kilowatt hour + long_name: kilowatt hour + symbols: + - kWh + GWH: + name: gigawatt hour + long_name: gigawatt hour + symbols: + - GWh + WTT: + name: watt + long_name: watt + symbols: + - W + KWT: + name: kilowatt + long_name: kilowatt + symbols: + - kW + MAW: + name: megawatt + long_name: megawatt + symbols: + - MW diff --git a/config/units-of-measure/locales/unece_es.yml b/config/units-of-measure/locales/unece_es.yml new file mode 100644 index 000000000..0f282a93a --- /dev/null +++ b/config/units-of-measure/locales/unece_es.yml @@ -0,0 +1,733 @@ +--- +unece_units: + XCU: + name: Tazas + XCN: + name: Contenedor + XSH: + name: Bolsa + X43: + name: Bigbag + XST: + name: Hoja + XOK: + name: Bloque + XVA: + name: IVA + XBX: + name: Caja + XBH: + name: Cintura + XBE: + name: Paquete + XCX: + name: Puede + XBJ: + name: Cubo + XUN: + name: Unidad + XOS: + name: Palé desechable + XDH: + name: Eurobox, CHEP-Box + XBA: + name: Barril + XFI: + name: Barriles + XBO: + name: Botella + XBQ: + name: Botella en embalaje exterior + XFB: + name: Flexibag + XFT: + name: Contenedor de alimentos + XJR: + name: Vidrio + XGR: + name: Tarro de cristal + XOW: + name: Sacos grandes en tamaño palé + X8B: + name: Caja de madera + XCV: + name: Sobre + XWA: + name: Contenedor intermedio a granel (IBC) + XEI: + name: Caja isotérmica + XJT: + name: Bolsa de yute + XGY: + name: Saco de yute + XJY: + name: Bidón + XBD: + name: Cartón + XCR: + name: Caja + XAI: + name: Envases con bisagras + XPA: + name: Collo + XBK: + name: Cesta + XBI: + name: Cubo + XOV: + name: Palé retornable + XNT: + name: Red + XPK: + name: Paquete + XPC: + name: Paquete + XPX: + name: Palé + X5M: + name: Bolsa de papel + XPR: + name: Contenedor de plástico + XEC: + name: Bolsa de plástico + X6H: + name: Envases de plástico compuesto + X44: + name: Bolsa de polietileno + XBR: + name: Perno + XCW: + name: Contenedor rodante + XBT: + name: Rollo + XSA: + name: Saco + XBM: + name: Tazón + XSX: + name: Establecer + XDN: + name: Dispensador + XAE: + name: Bote de spray + XSC: + name: Subida + XLU: + name: Escalera + X5L: + name: Bolsa de tela + XPP: + name: Pieza + XPU: + name: Bandeja + XBG: + name: Bolsillo + XP2: + name: Crisol + XCK: + name: Tonelada + XPT: + name: Olla + XGI: + name: Portador + XTU: + name: Tubo + PTN: + name: Porción + long_name: Porción + symbols: [] + STC: + name: Bar + long_name: Bar + symbols: [] + DMT: + name: Decimetro + long_name: Decimetro + symbols: + - dm + CMT: + name: Centímetros + long_name: Centímetros + symbols: + - cm + 4H: + name: Micrómetros + long_name: Micrómetro (micra) + symbols: + - µm + MMT: + name: Milímetros + long_name: Milímetros + symbols: + - mm + HMT: + name: Hectómetro + long_name: Hectómetro + symbols: + - hm + KMT: + name: Kilómetros + long_name: Kilómetros + symbols: + - km + A45: + name: Decámetro + long_name: Decámetro + symbols: + - dam + INH: + name: Pulgada + long_name: Pulgada + symbols: + - "″" + - in + FOT: + name: Pie + long_name: Pie + symbols: + - ft + YRD: + name: Patio + long_name: Patio + symbols: + - yd + SMI: + name: Milla + long_name: Milla (británica) + symbols: + - mile + '77': + name: Milipulgada + long_name: Milipulgada + symbols: + - mil + MTK: + name: Metros cuadrados + long_name: Metros cuadrados + symbols: + - m² + - qm + DAA: + name: Decar + long_name: Decar + symbols: + - daa + KMK: + name: Kilómetros cuadrados + long_name: Kilómetros cuadrados + symbols: + - km² + CMK: + name: Centímetros cuadrados + long_name: Centímetros cuadrados + symbols: + - cm² + DMK: + name: Decímetro cuadrado + long_name: Decímetro cuadrado + symbols: + - dm² + H16: + name: Decámetro cuadrado + long_name: Decámetro cuadrado + symbols: + - dam² + H18: + name: Hectómetro cuadrado + long_name: Hectómetro cuadrado + symbols: + - hm² + MMK: + name: Milímetro cuadrado + long_name: Milímetro cuadrado + symbols: + - mm² + M47: + name: Circular mil + long_name: Circular mil + symbols: + - cmil + ARE: + name: Ar + long_name: Ar + symbols: + - a + HAR: + name: Hectáreas + long_name: Hectáreas + symbols: + - ha + INK: + name: Pulgada cuadrada + long_name: Pulgada cuadrada + symbols: + - in² + FTK: + name: Pies cuadrados + long_name: Pies cuadrados + symbols: + - ft² + YDK: + name: Metros cuadrados + long_name: Metros cuadrados + symbols: + - yd² + MIK: + name: Milla cuadrada + long_name: Milla cuadrada (británica) + symbols: + - mi² + ACR: + name: Mañana + long_name: Mañana + symbols: + - acre + KGM: + name: Kilogramos + long_name: Kilogramos + symbols: + - kg + HGM: + name: Hectograma + long_name: Hectograma + symbols: + - hg + KTN: + name: Kilotones + long_name: Kilotones + symbols: + - kt + DJ: + name: Decagrama + long_name: Decagrama + symbols: + - dag + - dkg + DG: + name: Decigramo + long_name: Decigramo + symbols: + - dg + CGM: + name: Centigramo + long_name: Centigramo + symbols: + - cg + DTN: + name: Decitonne + long_name: Decitonne + symbols: + - dt + - dtn + MGM: + name: Miligramo + long_name: Miligramo + symbols: + - mg + 2U: + name: Megagrama + long_name: Megagrama + symbols: + - Mg + MC: + name: Microgramos + long_name: Microgramos + symbols: + - µg + GRM: + name: Gramos + long_name: Gramos + symbols: + - g + TNE: + name: Tonelada + long_name: Tonelada (métrica) + symbols: + - t + M86: + name: Libras + long_name: Libras + symbols: + - pfd + LBR: + name: Libra inglesa + long_name: Libra inglesa + symbols: + - lb + GRN: + name: Gran + long_name: Gran + symbols: + - gr + ONZ: + name: Onza + long_name: Onza (avoirdupois) + symbols: + - oz + CWI: + name: H. centner + long_name: Hundredweight (británico) + symbols: + - cwt + CWA: + name: Am. Zentner + long_name: Hundredweight (americano) + symbols: + - cwt + LTN: + name: Tonelada br + long_name: Tonelada británica, tonelada larga (americana) + symbols: + - ton (Br.) + STI: + name: Piedra + long_name: Piedra (británica) + symbols: + - st + STN: + name: Am. Tonelada + long_name: Tonelada americana, tonelada corta + symbols: + - ton (Am.) + APZ: + name: Onza troy + long_name: Onza troy u onza de boticario + symbols: + - tr oz + F13: + name: Babosa + long_name: Babosa + symbols: + - slug + SEC: + name: Segundo + long_name: Segundo [unidad de tiempo] + symbols: + - s + MIN: + name: Minuto + long_name: Minuto [unidad de tiempo] + symbols: + - min + HUR: + name: Hora + long_name: Hora + symbols: + - h + DAY: + name: Día + long_name: Día + symbols: + - d + C26: + name: Milisegundo + long_name: Milisegundo + symbols: + - ms + WEE: + name: Semana + long_name: Semana + symbols: + - wk + MON: + name: Mes + long_name: Mes + symbols: + - mo + ANN: + name: Año + long_name: Año + symbols: + - "y" + MTQ: + name: Metros cúbicos + long_name: Metros cúbicos + symbols: + - m³ + - cbm + LTR: + name: Litros + long_name: Litros + symbols: + - l + MAL: + name: Megalitros + long_name: Megalitros + symbols: + - Ml + DLT: + name: Decilitro + long_name: Decilitro + symbols: + - dl + 4G: + name: Microlitro + long_name: Microlitro + symbols: + - µl + K6: + name: Kilolitros + long_name: Kilolitros + symbols: + - kl + A44: + name: Decalitre + long_name: Decalitre + symbols: + - dal + MMQ: + name: Milímetros cúbicos + long_name: Milímetros cúbicos + symbols: + - mm³ + CMQ: + name: Centímetros cúbicos + long_name: Centímetros cúbicos + symbols: + - cm³ + - ccm + DMQ: + name: Decímetros cúbicos + long_name: Decímetros cúbicos + symbols: + - dm³ + MLT: + name: Mililitros + long_name: Mililitros + symbols: + - ml + HLT: + name: Hectolitro + long_name: Hectolitro + symbols: + - hl + CLT: + name: Centilitro + long_name: Centilitro + symbols: + - cl + DMA: + name: Decámetro cúbico + long_name: Decámetro cúbico + symbols: + - dam³ + H19: + name: Hektómetro cúbico + long_name: Hektómetro cúbico + symbols: + - hm³ + H20: + name: Kilómetros cúbicos + long_name: Kilómetros cúbicos + symbols: + - km³ + M67: + name: acre-pie + long_name: acre-pie (basado en U.S. Survey Foot) + symbols: + - acre-ft + M68: + name: Cordón + long_name: Cordón (128 pies3) + symbols: + - cord + M69: + name: Milla cúbica + long_name: Milla cúbica (británica) + symbols: + - mi³ + M70: + name: Cubo de registro + long_name: Cubo de registro + symbols: + - RT + 5I: + name: Pies cúbicos + long_name: Pies cúbicos + symbols: + - std + INQ: + name: Pulgada cúbica + long_name: Pulgada cúbica + symbols: + - in³ + FTQ: + name: Pies cúbicos + long_name: Pies cúbicos + symbols: + - ft³ + YDQ: + name: Metros cúbicos + long_name: Metros cúbicos + symbols: + - yd³ + GLI: + name: Galón (Br.) + long_name: Galón (británico) + symbols: + - gal + GLL: + name: Galón (Am.) + long_name: Galón (americano) + symbols: + - gal + PTI: + name: Pinta (Br.) + long_name: Pint (británica) + symbols: + - pt + QTI: + name: Cuarto de galón + long_name: cuarto de galón (británico) + symbols: + - qt + PTL: + name: pinta líquida (Am.) + long_name: pinta líquida (americana) + symbols: + - liq pt + QTL: + name: cuarto de galón líquido (Am.) + long_name: cuarto de galón líquido (americano) + symbols: + - liq qt + PTD: + name: pinta seca (Am.) + long_name: pinta seca (americana) + symbols: + - dry pt + OZI: + name: onza líquida (Br.) + long_name: onza líquida (británica) + symbols: + - fl oz + J57: + name: Barril (Br.) + long_name: Barril (británico) + symbols: + - bbl + L43: + name: Cuarto de fanega (Br.) + long_name: peck (británico) + symbols: + - pk + L84: + name: Tonelada de envío (Br.) + long_name: tonelada (envío al Reino Unido) + symbols: + - Shipping ton (Br.) + L86: + name: Tonelada de envío (Am.) + long_name: tonelada (envío a EE.UU.) + symbols: + - Shipping ton (Am.) + OZA: + name: Onza líquida + long_name: Onza líquida (americana) + symbols: + - fl oz + BUI: + name: Bushel (Br.) + long_name: Bushel (británico) + symbols: + - bushel + BUA: + name: Bushel (Am.) + long_name: Bushel (americano) + symbols: + - bu + BLL: + name: Barril (Am.) + long_name: Barril (americano) + symbols: + - barrel + BLD: + name: Barril seco (Am.) + long_name: Dry Barrel (americano) + symbols: + - bbl + GLD: + name: Galón seco (Am.) + long_name: Galón seco (americano) + symbols: + - dry gal + QTD: + name: Cuarto seco (Am.) + long_name: Cuarto de galón seco (americano) + symbols: + - dry qt + G26: + name: Ster + long_name: Ster (metro cúbico a granel) + symbols: + - st + G21: + name: Taza + long_name: Taza [unidad de volumen] + symbols: + - cup + G24: + name: Cucharada + long_name: Cucharada + symbols: + - cs + G25: + name: Cucharadita + long_name: Cucharadita + symbols: + - cdta. + G23: + name: Cuarto de fanega (Am.) + long_name: Cuarto de fanega (americano) + symbols: + - pk + JOU: + name: Julios + long_name: Julios + symbols: + - J + J75: + name: Calorías + long_name: Calorías + symbols: + - cal + K51: + name: Kilocalorías + long_name: Kilocalorías + symbols: + - kcal + J55: + name: Vatio segundo + long_name: Vatio segundo + symbols: + - Ws + WHR: + name: Vatio hora + long_name: Vatio hora + symbols: + - Wh + KWH: + name: Kilovatio hora + long_name: Kilovatio hora + symbols: + - kWh + GWH: + name: Gigavatios hora + long_name: Gigavatios hora + symbols: + - GWh + WTT: + name: Vatios + long_name: Vatios + symbols: + - W + KWT: + name: Kilovatios + long_name: Kilovatios + symbols: + - kW + MAW: + name: Megavatios + long_name: Megavatios + symbols: + - MW diff --git a/config/units-of-measure/locales/unece_fr.yml b/config/units-of-measure/locales/unece_fr.yml new file mode 100644 index 000000000..4cbecad9f --- /dev/null +++ b/config/units-of-measure/locales/unece_fr.yml @@ -0,0 +1,733 @@ +--- +unece_units: + XCU: + name: Gobelets + XCN: + name: Récipient + XSH: + name: Sacs + X43: + name: Bigbag + XST: + name: Feuille + XOK: + name: Bloc + XVA: + name: Cuve + XBX: + name: Boîte + XBH: + name: Confédération + XBE: + name: Faisceau + XCX: + name: Boîte + XBJ: + name: Seau + XUN: + name: Unité + XOS: + name: Palette à usage unique + XDH: + name: Eurobox, CHEP-Box + XBA: + name: Tonneau + XFI: + name: Fûts + XBO: + name: Bouteille + XBQ: + name: Bouteille en suremballage + XFB: + name: Flexibag + XFT: + name: Foodtainer + XJR: + name: Verre + XGR: + name: Récipient en verre + XOW: + name: Grand sac de la taille d'une palette + X8B: + name: Caisse en bois + XCV: + name: Étui + XWA: + name: Conteneur intermédiaire de vrac (IBC) + XEI: + name: Boîte isotherme + XJT: + name: Sac en jute + XGY: + name: Sac en jute + XJY: + name: Bidons + XBD: + name: Carton + XCR: + name: Caisse + XAI: + name: Emballage à rabat + XPA: + name: Kollo + XBK: + name: Panier + XBI: + name: Benne + XOV: + name: Palette réutilisable + XNT: + name: Réseau + XPK: + name: Emballage + XPC: + name: Paquet + XPX: + name: Palette + X5M: + name: Sac en papier + XPR: + name: Récipient en plastique + XEC: + name: Sac en plastique + X6H: + name: Emballage plastique composite + X44: + name: Sacs en polyéthylène + XBR: + name: Verrou + XCW: + name: Conteneurs roulants + XBT: + name: Rouleau + XSA: + name: Sac + XBM: + name: Bol + XSX: + name: Set + XDN: + name: Distributeur + XAE: + name: Bombe aérosol + XSC: + name: Montée + XLU: + name: Escalier + X5L: + name: Sac en tissu + XPP: + name: Pièces + XPU: + name: Bol + XBG: + name: Sac + XP2: + name: Creuset + XCK: + name: Tonne + XPT: + name: Pot + XGI: + name: Poutrelles + XTU: + name: Tube + PTN: + name: Portion + long_name: Portion + symbols: [] + STC: + name: Tige + long_name: Tige + symbols: [] + DMT: + name: Décimètre + long_name: Décimètre + symbols: + - dm + CMT: + name: Centimètres + long_name: Centimètres + symbols: + - cm + 4H: + name: Micromètre + long_name: Micromètre (micron) + symbols: + - µm + MMT: + name: Millimètres + long_name: Millimètres + symbols: + - mm + HMT: + name: Hectomètre + long_name: Hectomètre + symbols: + - hm + KMT: + name: Kilomètres + long_name: Kilomètres + symbols: + - km + A45: + name: Décamètre + long_name: Décamètre + symbols: + - dam + INH: + name: Pouce + long_name: Pouce + symbols: + - "″" + - in + FOT: + name: Pied + long_name: Pied + symbols: + - ft + YRD: + name: Yard + long_name: Yard + symbols: + - yd + SMI: + name: Mile + long_name: Mile (britannique) + symbols: + - mile + '77': + name: Millizoll + long_name: Millizoll + symbols: + - mil + MTK: + name: Mètres carrés + long_name: Mètres carrés + symbols: + - m² + - qm + DAA: + name: Dekar + long_name: Dekar + symbols: + - daa + KMK: + name: Kilomètre carré + long_name: Kilomètre carré + symbols: + - km² + CMK: + name: Centimètres carrés + long_name: Centimètres carrés + symbols: + - cm² + DMK: + name: Décimètre carré + long_name: Décimètre carré + symbols: + - dm² + H16: + name: Décamètre carré + long_name: Décamètre carré + symbols: + - dam² + H18: + name: Hectomètre carré + long_name: Hectomètre carré + symbols: + - hm² + MMK: + name: Millimètre carré + long_name: Millimètre carré + symbols: + - mm² + M47: + name: Mils circulaires + long_name: Mils circulaires + symbols: + - cmil + ARE: + name: Ar + long_name: Ar + symbols: + - a + HAR: + name: Hectares + long_name: Hectares + symbols: + - ha + INK: + name: Pouce carré + long_name: Pouce carré + symbols: + - in² + FTK: + name: Pieds carrés + long_name: Pieds carrés + symbols: + - ft² + YDK: + name: Mètres carrés + long_name: Mètres carrés + symbols: + - yd² + MIK: + name: Mille carré + long_name: Mille carré (britannique) + symbols: + - mi² + ACR: + name: Demain + long_name: Demain + symbols: + - acre + KGM: + name: Kilogramme + long_name: Kilogramme + symbols: + - kg + HGM: + name: Hectogramme + long_name: Hectogramme + symbols: + - hg + KTN: + name: Kilotonne + long_name: Kilotonne + symbols: + - kt + DJ: + name: Décagramme + long_name: Décagramme + symbols: + - dag + - dkg + DG: + name: Décigramme + long_name: Décigramme + symbols: + - dg + CGM: + name: Centigramme + long_name: Centigramme + symbols: + - cg + DTN: + name: Décitonne + long_name: Décitonne + symbols: + - dt + - dtn + MGM: + name: Milligramme + long_name: Milligramme + symbols: + - mg + 2U: + name: Mégagramme + long_name: Mégagramme + symbols: + - Mg + MC: + name: Microgramme + long_name: Microgramme + symbols: + - µg + GRM: + name: Grammes + long_name: Grammes + symbols: + - g + TNE: + name: Tonne + long_name: Tonne (métrique) + symbols: + - t + M86: + name: Livre + long_name: Livre + symbols: + - pfd + LBR: + name: Livre anglaise + long_name: Livre anglaise + symbols: + - lb + GRN: + name: Gran + long_name: Gran + symbols: + - gr + ONZ: + name: Once + long_name: Once (avoirdupois) + symbols: + - oz + CWI: + name: Br. centenaire + long_name: Hundredweight (britannique) + symbols: + - cwt + CWA: + name: Le . Quintaux + long_name: Hundredweight (américain) + symbols: + - cwt + LTN: + name: Br. tonne + long_name: Tonne britannique, Long Ton (américain) + symbols: + - ton (Br.) + STI: + name: Pierre + long_name: Pierre (britannique) + symbols: + - st + STN: + name: Am. Tonne + long_name: Tonne américaine, short ton + symbols: + - ton (Am.) + APZ: + name: Once troy + long_name: Once troy ou once d'apothicaire + symbols: + - tr oz + F13: + name: Slug + long_name: Slug + symbols: + - slug + SEC: + name: Seconde + long_name: Seconde [unité de temps] + symbols: + - s + MIN: + name: Minute + long_name: Minute [unité de temps] + symbols: + - min + HUR: + name: Heure + long_name: Heure + symbols: + - h + DAY: + name: Jour + long_name: Jour + symbols: + - d + C26: + name: Milliseconde + long_name: Milliseconde + symbols: + - ms + WEE: + name: Semaine + long_name: Semaine + symbols: + - wk + MON: + name: Mois + long_name: Mois + symbols: + - mo + ANN: + name: Année + long_name: Année + symbols: + - "y" + MTQ: + name: Mètres cubes + long_name: Mètres cubes + symbols: + - m³ + - cbm + LTR: + name: Litres + long_name: Litres + symbols: + - l + MAL: + name: Mégalitre + long_name: Mégalitre + symbols: + - Ml + DLT: + name: Décilitre + long_name: Décilitre + symbols: + - dl + 4G: + name: Microlitre + long_name: Microlitre + symbols: + - µl + K6: + name: Kilolitre + long_name: Kilolitre + symbols: + - kl + A44: + name: Décalitre + long_name: Décalitre + symbols: + - dal + MMQ: + name: Millimètre cube + long_name: Millimètre cube + symbols: + - mm³ + CMQ: + name: Centimètre cube + long_name: Centimètre cube + symbols: + - cm³ + - ccm + DMQ: + name: Décimètre cube + long_name: Décimètre cube + symbols: + - dm³ + MLT: + name: Millilitres + long_name: Millilitres + symbols: + - ml + HLT: + name: Hectolitre + long_name: Hectolitre + symbols: + - hl + CLT: + name: Centilitre + long_name: Centilitre + symbols: + - cl + DMA: + name: Décamètre cube + long_name: Décamètre cube + symbols: + - dam³ + H19: + name: Hectomètre cube + long_name: Hectomètre cube + symbols: + - hm³ + H20: + name: Kilomètre cube + long_name: Kilomètre cube + symbols: + - km³ + M67: + name: acre-pied + long_name: acre-foot (basé sur U.S. Survey Foot) + symbols: + - acre-ft + M68: + name: Cordon + long_name: Cordon (128 ft3) + symbols: + - cord + M69: + name: Mille cube + long_name: Mille cube (britannique) + symbols: + - mi³ + M70: + name: Tonneau à registre + long_name: Tonneau à registre + symbols: + - RT + 5I: + name: Pieds cubes + long_name: Pieds cubes + symbols: + - std + INQ: + name: Pouce cube + long_name: Pouce cube + symbols: + - in³ + FTQ: + name: Pieds cubes + long_name: Pieds cubes + symbols: + - ft³ + YDQ: + name: Mètres cubes + long_name: Mètres cubes + symbols: + - yd³ + GLI: + name: Gallon (Br.) + long_name: Gallon (britannique) + symbols: + - gal + GLL: + name: Gallon (Am.) + long_name: Gallon (américain) + symbols: + - gal + PTI: + name: Pint (Br.) + long_name: Pint (britannique) + symbols: + - pt + QTI: + name: Quart + long_name: quart (britannique) + symbols: + - qt + PTL: + name: pinte liquide (am.) + long_name: pinte liquide (américaine) + symbols: + - liq pt + QTL: + name: quart liquide (am.) + long_name: quart liquide (américain) + symbols: + - liq qt + PTD: + name: pinte sèche (am.) + long_name: pinte sèche (américaine) + symbols: + - dry pt + OZI: + name: once liquide (br.) + long_name: once liquide (britannique) + symbols: + - fl oz + J57: + name: Baril (Br.) + long_name: Baril (britannique) + symbols: + - bbl + L43: + name: Quart de boisseau (Br.) + long_name: peck (britannique) + symbols: + - pk + L84: + name: Shipping ton (Br.) + long_name: ton (UK shipping) + symbols: + - Shipping ton (Br.) + L86: + name: Shipping ton (Am.) + long_name: ton (US shipping) + symbols: + - Shipping ton (Am.) + OZA: + name: Once liquide + long_name: Once liquide (américain) + symbols: + - fl oz + BUI: + name: Boisseau (Br.) + long_name: Boisseau (britannique) + symbols: + - bushel + BUA: + name: Boisseau (am.) + long_name: Boisseau (américain) + symbols: + - bu + BLL: + name: Baril (Am.) + long_name: Baril (américain) + symbols: + - barrel + BLD: + name: Dry Barrel (Am.) + long_name: Dry Barrel (américain) + symbols: + - bbl + GLD: + name: Dry Gallon (Am.) + long_name: Dry Gallon (américain) + symbols: + - dry gal + QTD: + name: Quart sec (Am.) + long_name: Dry Quart (américain) + symbols: + - dry qt + G26: + name: Ster + long_name: Stère (mètre cube en vrac) + symbols: + - st + G21: + name: Tasse + long_name: Tasse [unité de volume] + symbols: + - cup + G24: + name: Cuillère à soupe + long_name: Cuillère à soupe + symbols: + - cs + G25: + name: Cuillère à café + long_name: Cuillère à café + symbols: + - cc + G23: + name: Quart de boisseau (Am.) + long_name: Quart de boisseau (américain) + symbols: + - pk + JOU: + name: Joule + long_name: Joule + symbols: + - J + J75: + name: Calorie + long_name: Calorie + symbols: + - cal + K51: + name: Kilocalorie + long_name: Kilocalorie + symbols: + - kcal + J55: + name: Wattseconde + long_name: Wattseconde + symbols: + - Ws + WHR: + name: Watt-heure + long_name: Watt-heure + symbols: + - Wh + KWH: + name: Kilowattheure + long_name: Kilowattheure + symbols: + - kWh + GWH: + name: Gigawatt-heure + long_name: Gigawatt-heure + symbols: + - GWh + WTT: + name: Watt + long_name: Watt + symbols: + - W + KWT: + name: Kilowatt + long_name: Kilowatt + symbols: + - kW + MAW: + name: Mégawatt + long_name: Mégawatt + symbols: + - MW diff --git a/config/units-of-measure/locales/unece_nl.yml b/config/units-of-measure/locales/unece_nl.yml new file mode 100644 index 000000000..c9d74b855 --- /dev/null +++ b/config/units-of-measure/locales/unece_nl.yml @@ -0,0 +1,733 @@ +--- +unece_units: + XCU: + name: Bekers + XCN: + name: Container + XSH: + name: Zak + X43: + name: Bigbag + XST: + name: Blad + XOK: + name: Blok + XVA: + name: BTW + XBX: + name: Box + XBH: + name: Tailleband + XBE: + name: Bundel + XCX: + name: Kan + XBJ: + name: Emmer + XUN: + name: Eenheid + XOS: + name: Wegwerppallet + XDH: + name: Eurobox, CHEP-Box + XBA: + name: Vat + XFI: + name: Vaten + XBO: + name: Fles + XBQ: + name: Fles in buitenverpakking + XFB: + name: Flexibag + XFT: + name: Foodtainer + XJR: + name: Glas + XGR: + name: Glazen pot + XOW: + name: Grote zak in palletformaat + X8B: + name: Houten doos + XCV: + name: Envelop + XWA: + name: IBC (Intermediate Bulk Container) + XEI: + name: Isotherme doos + XJT: + name: Jute zak + XGY: + name: Jute zak + XJY: + name: Bus + XBD: + name: Karton + XCR: + name: Krat + XAI: + name: Scharnierende verpakking + XPA: + name: Collo + XBK: + name: Mand + XBI: + name: Emmer + XOV: + name: Retourpallet + XNT: + name: Net + XPK: + name: Pak + XPC: + name: Pakket + XPX: + name: Pallet + X5M: + name: Papieren zak + XPR: + name: Plastic verpakking + XEC: + name: Plastic zak + X6H: + name: Kunststof composiet verpakking + X44: + name: Polyester zak + XBR: + name: Bout + XCW: + name: Container op rol + XBT: + name: Rol + XSA: + name: Zak + XBM: + name: Kom + XSX: + name: Stel in + XDN: + name: Verdeler + XAE: + name: Spuitbus + XSC: + name: Stijging + XLU: + name: Trap + X5L: + name: Doek + XPP: + name: Stuk + XPU: + name: Lade + XBG: + name: Zak + XP2: + name: Kroes + XCK: + name: Ton + XPT: + name: Pot + XGI: + name: Drager + XTU: + name: Buis + PTN: + name: Portie + long_name: Portie + symbols: [] + STC: + name: Bar + long_name: Bar + symbols: [] + DMT: + name: Decimeter + long_name: Decimeter + symbols: + - dm + CMT: + name: Centimeters + long_name: Centimeters + symbols: + - cm + 4H: + name: Micrometers + long_name: Micrometer (micron) + symbols: + - µm + MMT: + name: Millimeters + long_name: Millimeters + symbols: + - mm + HMT: + name: Hectometer + long_name: Hectometer + symbols: + - hm + KMT: + name: Kilometers + long_name: Kilometers + symbols: + - km + A45: + name: Decameter + long_name: Decameter + symbols: + - dam + INH: + name: Inch + long_name: Inch + symbols: + - "″" + - in + FOT: + name: Voet + long_name: Voet + symbols: + - ft + YRD: + name: Werf + long_name: Werf + symbols: + - yd + SMI: + name: Mijl + long_name: Mijl (Brits) + symbols: + - mile + '77': + name: Milli inch + long_name: Milli inch + symbols: + - mil + MTK: + name: Vierkante meter + long_name: Vierkante meter + symbols: + - m² + - qm + DAA: + name: Decar + long_name: Decar + symbols: + - daa + KMK: + name: Vierkante kilometer + long_name: Vierkante kilometer + symbols: + - km² + CMK: + name: Vierkante centimeters + long_name: Vierkante centimeters + symbols: + - cm² + DMK: + name: Vierkante decimeter + long_name: Vierkante decimeter + symbols: + - dm² + H16: + name: Vierkante decameter + long_name: Vierkante decameter + symbols: + - dam² + H18: + name: Vierkante hectometer + long_name: Vierkante hectometer + symbols: + - hm² + MMK: + name: Vierkante millimeter + long_name: Vierkante millimeter + symbols: + - mm² + M47: + name: Cirkelvormige mil + long_name: Cirkelvormige mil + symbols: + - cmil + ARE: + name: Ar + long_name: Ar + symbols: + - a + HAR: + name: Hectare + long_name: Hectare + symbols: + - ha + INK: + name: Vierkante inch + long_name: Vierkante inch + symbols: + - in² + FTK: + name: Vierkante voet + long_name: Vierkante voet + symbols: + - ft² + YDK: + name: Vierkante meter + long_name: Vierkante meter + symbols: + - yd² + MIK: + name: Vierkante mijl + long_name: Vierkante mijl (Brits) + symbols: + - mi² + ACR: + name: Morgen + long_name: Morgen + symbols: + - acre + KGM: + name: Kilogram + long_name: Kilogram + symbols: + - kg + HGM: + name: Hectogram + long_name: Hectogram + symbols: + - hg + KTN: + name: Kiloton + long_name: Kiloton + symbols: + - kt + DJ: + name: Decagram + long_name: Decagram + symbols: + - dag + - dkg + DG: + name: Decigram + long_name: Decigram + symbols: + - dg + CGM: + name: Centigram + long_name: Centigram + symbols: + - cg + DTN: + name: Decitonne + long_name: Decitonne + symbols: + - dt + - dtn + MGM: + name: Milligram + long_name: Milligram + symbols: + - mg + 2U: + name: Megagram + long_name: Megagram + symbols: + - Mg + MC: + name: Microgram + long_name: Microgram + symbols: + - µg + GRM: + name: Gram + long_name: Gram + symbols: + - g + TNE: + name: Ton + long_name: Ton (metrisch) + symbols: + - t + M86: + name: Pond + long_name: Pond + symbols: + - pfd + LBR: + name: Engels pond + long_name: Engels pond + symbols: + - lb + GRN: + name: Gran + long_name: Gran + symbols: + - gr + ONZ: + name: Ons + long_name: Ounce (avoirdupois) + symbols: + - oz + CWI: + name: Br. centner + long_name: Honderd kilogram (Brits) + symbols: + - cwt + CWA: + name: Am. Zentner + long_name: Honderd kilogram (Amerikaans) + symbols: + - cwt + LTN: + name: Br. ton + long_name: Britse ton, lange ton (Amerikaans) + symbols: + - ton (Br.) + STI: + name: Steen + long_name: Steen (Brits) + symbols: + - st + STN: + name: Am. Ton + long_name: Amerikaanse ton, korte ton + symbols: + - ton (Am.) + APZ: + name: Troy ounce + long_name: Troy ounce of apothekersunce + symbols: + - tr oz + F13: + name: Slak + long_name: Slak + symbols: + - slug + SEC: + name: Tweede + long_name: Seconde [tijdseenheid] + symbols: + - s + MIN: + name: Minuut + long_name: Minuut [tijdseenheid] + symbols: + - min + HUR: + name: Uur + long_name: Uur + symbols: + - h + DAY: + name: Dag + long_name: Dag + symbols: + - d + C26: + name: Milliseconde + long_name: Milliseconde + symbols: + - ms + WEE: + name: Week + long_name: Week + symbols: + - wk + MON: + name: Maand + long_name: Maand + symbols: + - mo + ANN: + name: Jaar + long_name: Jaar + symbols: + - "y" + MTQ: + name: Kubieke meter + long_name: Kubieke meter + symbols: + - m³ + - cbm + LTR: + name: Liter + long_name: Liter + symbols: + - l + MAL: + name: Megaliter + long_name: Megaliter + symbols: + - Ml + DLT: + name: Deciliter + long_name: Deciliter + symbols: + - dl + 4G: + name: Microliter + long_name: Microliter + symbols: + - µl + K6: + name: Kiloliter + long_name: Kiloliter + symbols: + - kl + A44: + name: Decaliter + long_name: Decaliter + symbols: + - dal + MMQ: + name: Kubieke millimeter + long_name: Kubieke millimeter + symbols: + - mm³ + CMQ: + name: Kubieke centimeter + long_name: Kubieke centimeter + symbols: + - cm³ + - ccm + DMQ: + name: Kubieke decimeter + long_name: Kubieke decimeter + symbols: + - dm³ + MLT: + name: Milliliters + long_name: Milliliters + symbols: + - ml + HLT: + name: Hectoliter + long_name: Hectoliter + symbols: + - hl + CLT: + name: Centiliter + long_name: Centiliter + symbols: + - cl + DMA: + name: Kubische decameter + long_name: Kubische decameter + symbols: + - dam³ + H19: + name: Kubieke hektometer + long_name: Kubieke hektometer + symbols: + - hm³ + H20: + name: Kubieke kilometer + long_name: Kubieke kilometer + symbols: + - km³ + M67: + name: acre-voet + long_name: acre-foot (gebaseerd op U.S. Survey Foot) + symbols: + - acre-ft + M68: + name: Snoer + long_name: Snoer (128 ft3) + symbols: + - cord + M69: + name: Kubieke mijl + long_name: Kubieke mijl (Brits) + symbols: + - mi³ + M70: + name: Bak registreren + long_name: Bak registreren + symbols: + - RT + 5I: + name: Kubieke voet + long_name: Kubieke voet + symbols: + - std + INQ: + name: Kubieke inch + long_name: Kubieke inch + symbols: + - in³ + FTQ: + name: Kubieke voet + long_name: Kubieke voet + symbols: + - ft³ + YDQ: + name: Kubieke meter + long_name: Kubieke meter + symbols: + - yd³ + GLI: + name: Gallon (Br.) + long_name: Gallon (Brits) + symbols: + - gal + GLL: + name: Gallon (Am.) + long_name: Gallon (Amerikaans) + symbols: + - gal + PTI: + name: Pint (Br.) + long_name: Pint (Brits) + symbols: + - pt + QTI: + name: Kwart + long_name: kwart (Brits) + symbols: + - qt + PTL: + name: vloeibare pint (Am.) + long_name: vloeibare pint (Amerikaans) + symbols: + - liq pt + QTL: + name: vloeibaar kwart (Am.) + long_name: vloeibaar kwart (amerikaans) + symbols: + - liq qt + PTD: + name: droge pint (Am.) + long_name: droge pint (Amerikaans) + symbols: + - dry pt + OZI: + name: vloeibare ounce (Br.) + long_name: fluid ounce (Brits) + symbols: + - fl oz + J57: + name: Vat (Br.) + long_name: Vat (Brits) + symbols: + - bbl + L43: + name: Kwart bushel (Br.) + long_name: peck (Brits) + symbols: + - pk + L84: + name: Ton (Br.) + long_name: ton (verzending UK) + symbols: + - Shipping ton (Br.) + L86: + name: Ton (Am.) + long_name: ton (verzending VS) + symbols: + - Shipping ton (Am.) + OZA: + name: Vloeibare ounce + long_name: Vloeibare ounce (Amerikaans) + symbols: + - fl oz + BUI: + name: Bushel (Br.) + long_name: Bushel (Brits) + symbols: + - bushel + BUA: + name: Bushel (Am.) + long_name: Bushel (Amerikaans) + symbols: + - bu + BLL: + name: Vat (Am.) + long_name: Vat (Amerikaans) + symbols: + - barrel + BLD: + name: Droog vat (Am.) + long_name: Dry Barrel (Amerikaans) + symbols: + - bbl + GLD: + name: Droge gallon (Am.) + long_name: Droge gallon (Amerikaans) + symbols: + - dry gal + QTD: + name: Droog Kwart (Am.) + long_name: Dry Quart (Amerikaans) + symbols: + - dry qt + G26: + name: Ster + long_name: Ster (kubieke meter bulk) + symbols: + - st + G21: + name: Beker + long_name: Cup [eenheid van volume] + symbols: + - cup + G24: + name: Eetlepel + long_name: Eetlepel + symbols: + - el + G25: + name: Theelepel + long_name: Theelepel + symbols: + - tl + G23: + name: Kwart bushel (Am.) + long_name: Quarter bushel (Amerikaans) + symbols: + - pk + JOU: + name: Joules + long_name: Joules + symbols: + - J + J75: + name: Calorieën + long_name: Calorieën + symbols: + - cal + K51: + name: Kilocalorie + long_name: Kilocalorie + symbols: + - kcal + J55: + name: Watt seconde + long_name: Watt seconde + symbols: + - Ws + WHR: + name: Wattuur + long_name: Wattuur + symbols: + - Wh + KWH: + name: Kilowattuur + long_name: Kilowattuur + symbols: + - kWh + GWH: + name: Gigawattuur + long_name: Gigawattuur + symbols: + - GWh + WTT: + name: Watts + long_name: Watts + symbols: + - W + KWT: + name: Kilowatt + long_name: Kilowatt + symbols: + - kW + MAW: + name: Megawatt + long_name: Megawatt + symbols: + - MW diff --git a/config/units-of-measure/locales/unece_tr.yml b/config/units-of-measure/locales/unece_tr.yml new file mode 100644 index 000000000..207fb32a5 --- /dev/null +++ b/config/units-of-measure/locales/unece_tr.yml @@ -0,0 +1,733 @@ +--- +unece_units: + XCU: + name: Bardaklar + XCN: + name: Konteyner + XSH: + name: Çanta + X43: + name: Bigbag + XST: + name: Levha + XOK: + name: Blok + XVA: + name: Vat + XBX: + name: Kutu + XBH: + name: Bel bandı + XBE: + name: Paket + XCX: + name: Can + XBJ: + name: Kova + XUN: + name: Birim + XOS: + name: Tek kullanımlık palet + XDH: + name: Eurobox, CHEP-Box + XBA: + name: Fıçı + XFI: + name: Variller + XBO: + name: Şişe + XBQ: + name: Dış ambalajında şişe + XFB: + name: Flexibag + XFT: + name: Foodtainer + XJR: + name: Cam + XGR: + name: Cam kavanoz + XOW: + name: Palet boyutunda büyük çuval + X8B: + name: Ahşap kutu + XCV: + name: Zarf + XWA: + name: Ara Dökme Konteyner (IBC) + XEI: + name: İzotermal kutu + XJT: + name: Jüt çanta + XGY: + name: Jüt çuval + XJY: + name: Teneke Kutu + XBD: + name: Karton + XCR: + name: Sandık + XAI: + name: Menteşeli ambalaj + XPA: + name: Kollo + XBK: + name: Sepet + XBI: + name: Kova + XOV: + name: İade edilebilir palet + XNT: + name: Şebeke + XPK: + name: Paket + XPC: + name: Paket + XPX: + name: PALET + X5M: + name: Kağıt torba + XPR: + name: Plastik kap + XEC: + name: Plastik torba + X6H: + name: Plastik kompozit ambalajlar + X44: + name: Çoklu Torba + XBR: + name: Cıvata + XCW: + name: Rulo konteyner + XBT: + name: Rulo + XSA: + name: Çuval + XBM: + name: Kase + XSX: + name: Set + XDN: + name: Dağıtıcı + XAE: + name: Sprey kutusu + XSC: + name: Yükseliş + XLU: + name: Merdiven + X5L: + name: Bez çanta + XPP: + name: Parça + XPU: + name: Tepsi + XBG: + name: Cep + XP2: + name: Pota + XCK: + name: Ton + XPT: + name: Tencere + XGI: + name: Taşıyıcı + XTU: + name: Tüp + PTN: + name: Porsiyon + long_name: Porsiyon + symbols: [] + STC: + name: Bar + long_name: Bar + symbols: [] + DMT: + name: Desimetre + long_name: Desimetre + symbols: + - dm + CMT: + name: Santimetre + long_name: Santimetre + symbols: + - cm + 4H: + name: Mikrometreler + long_name: Mikrometre (mikron) + symbols: + - µm + MMT: + name: Milimetre + long_name: Milimetre + symbols: + - mm + HMT: + name: Hektometre + long_name: Hektometre + symbols: + - hm + KMT: + name: Kilometre + long_name: Kilometre + symbols: + - km + A45: + name: Dekametre + long_name: Dekametre + symbols: + - dam + INH: + name: Inç + long_name: Inç + symbols: + - "″" + - in + FOT: + name: Ayak + long_name: Ayak + symbols: + - ft + YRD: + name: Bahçe + long_name: Bahçe + symbols: + - yd + SMI: + name: Mil + long_name: Mile (İngiliz) + symbols: + - mile + '77': + name: Milli inç + long_name: Milli inç + symbols: + - mil + MTK: + name: Metrekare + long_name: Metrekare + symbols: + - m² + - qm + DAA: + name: Decar + long_name: Decar + symbols: + - daa + KMK: + name: Kilometre kare + long_name: Kilometre kare + symbols: + - km² + CMK: + name: Santimetre kare + long_name: Santimetre kare + symbols: + - cm² + DMK: + name: Kare desimetre + long_name: Kare desimetre + symbols: + - dm² + H16: + name: Kare dekametre + long_name: Kare dekametre + symbols: + - dam² + H18: + name: Hektometre kare + long_name: Hektometre kare + symbols: + - hm² + MMK: + name: Kare milimetre + long_name: Kare milimetre + symbols: + - mm² + M47: + name: Dairesel mil + long_name: Dairesel mil + symbols: + - cmil + ARE: + name: Ar + long_name: Ar + symbols: + - a + HAR: + name: Hektar + long_name: Hektar + symbols: + - ha + INK: + name: İnç kare + long_name: İnç kare + symbols: + - in² + FTK: + name: Fit kare + long_name: Fit kare + symbols: + - ft² + YDK: + name: Metrekare + long_name: Metrekare + symbols: + - yd² + MIK: + name: Mil kare + long_name: Mil kare (İngiliz) + symbols: + - mi² + ACR: + name: Yarın + long_name: Yarın + symbols: + - acre + KGM: + name: Kilogram + long_name: Kilogram + symbols: + - kg + HGM: + name: Hektogram + long_name: Hektogram + symbols: + - hg + KTN: + name: Kiloton + long_name: Kiloton + symbols: + - kt + DJ: + name: Decagram + long_name: Decagram + symbols: + - dag + - dkg + DG: + name: Decigram + long_name: Decigram + symbols: + - dg + CGM: + name: Santigram + long_name: Santigram + symbols: + - cg + DTN: + name: Decitonne + long_name: Decitonne + symbols: + - dt + - dtn + MGM: + name: Miligram + long_name: Miligram + symbols: + - mg + 2U: + name: Megagram + long_name: Megagram + symbols: + - Mg + MC: + name: Mikrogram + long_name: Mikrogram + symbols: + - µg + GRM: + name: Grammes + long_name: Grammes + symbols: + - g + TNE: + name: Ton + long_name: Ton (metrik) + symbols: + - t + M86: + name: Pound + long_name: Pound + symbols: + - pfd + LBR: + name: İngiliz Sterlini + long_name: İngiliz Sterlini + symbols: + - lb + GRN: + name: Büyükanne + long_name: Büyükanne + symbols: + - gr + ONZ: + name: Ons + long_name: Ons (avoirdupois) + symbols: + - oz + CWI: + name: Br. centner + long_name: Yüzsiklet (İngiliz) + symbols: + - cwt + CWA: + name: Am. Zentner + long_name: Hundredweight (Amerikan) + symbols: + - cwt + LTN: + name: Br. ton + long_name: İngiliz tonu, uzun ton (Amerikan) + symbols: + - ton (Br.) + STI: + name: Taş + long_name: Stone (İngiliz) + symbols: + - st + STN: + name: Am. Ton + long_name: Amerikan ton, kısa ton + symbols: + - ton (Am.) + APZ: + name: Troy ons + long_name: Troy ons veya eczacı onsu + symbols: + - tr oz + F13: + name: Sümüklüböcek + long_name: Sümüklüböcek + symbols: + - slug + SEC: + name: Ikinci + long_name: Saniye [zaman birimi] + symbols: + - s + MIN: + name: Dakika + long_name: Dakika [zaman birimi] + symbols: + - min + HUR: + name: Saat + long_name: Saat + symbols: + - h + DAY: + name: Gün + long_name: Gün + symbols: + - d + C26: + name: Milisaniye + long_name: Milisaniye + symbols: + - ms + WEE: + name: Hafta + long_name: Hafta + symbols: + - wk + MON: + name: Ay + long_name: Ay + symbols: + - mo + ANN: + name: Yıl + long_name: Yıl + symbols: + - "y" + MTQ: + name: Metreküp + long_name: Metreküp + symbols: + - m³ + - cbm + LTR: + name: Litre + long_name: Litre + symbols: + - l + MAL: + name: Megalitre + long_name: Megalitre + symbols: + - Ml + DLT: + name: Desilitre + long_name: Desilitre + symbols: + - dl + 4G: + name: Mikrolitre + long_name: Mikrolitre + symbols: + - µl + K6: + name: Kilolitre + long_name: Kilolitre + symbols: + - kl + A44: + name: Decalitre + long_name: Decalitre + symbols: + - dal + MMQ: + name: Milimetre küp + long_name: Milimetre küp + symbols: + - mm³ + CMQ: + name: Santimetre küp + long_name: Santimetre küp + symbols: + - cm³ + - ccm + DMQ: + name: Kübik desimetre + long_name: Kübik desimetre + symbols: + - dm³ + MLT: + name: Mililitre + long_name: Mililitre + symbols: + - ml + HLT: + name: Hektolitre + long_name: Hektolitre + symbols: + - hl + CLT: + name: Santilitre + long_name: Santilitre + symbols: + - cl + DMA: + name: Kübik dekametre + long_name: Kübik dekametre + symbols: + - dam³ + H19: + name: Kübik hektometre + long_name: Kübik hektometre + symbols: + - hm³ + H20: + name: Kilometre küp + long_name: Kilometre küp + symbols: + - km³ + M67: + name: akre-ayak + long_name: acre-foot (U.S. Survey Foot'a göre) + symbols: + - acre-ft + M68: + name: Kordon + long_name: Kordon (128 ft3) + symbols: + - cord + M69: + name: Kübik mil + long_name: Kübik mil (İngiliz) + symbols: + - mi³ + M70: + name: Kayıt kutusu + long_name: Kayıt kutusu + symbols: + - RT + 5I: + name: Fit küp + long_name: Fit küp + symbols: + - std + INQ: + name: Kübik inç + long_name: Kübik inç + symbols: + - in³ + FTQ: + name: Fit küp + long_name: Fit küp + symbols: + - ft³ + YDQ: + name: Metreküp + long_name: Metreküp + symbols: + - yd³ + GLI: + name: Galon (Br.) + long_name: Galon (İngiliz) + symbols: + - gal + GLL: + name: Galon (Am.) + long_name: Galon (Amerikan) + symbols: + - gal + PTI: + name: Pint (Br.) + long_name: Pint (İngiliz) + symbols: + - pt + QTI: + name: Quart + long_name: quart (İngiliz) + symbols: + - qt + PTL: + name: sıvı pint (Am.) + long_name: sıvı pint (Amerikan) + symbols: + - liq pt + QTL: + name: sıvı litre (Am.) + long_name: sıvı quart (amerikan) + symbols: + - liq qt + PTD: + name: kuru pint (Am.) + long_name: kuru pint (Amerikan) + symbols: + - dry pt + OZI: + name: sıvı ons (Br.) + long_name: sıvı ons (İngiliz) + symbols: + - fl oz + J57: + name: Fıçı (Br.) + long_name: Varil (İngiliz) + symbols: + - bbl + L43: + name: Çeyrek kile (Br.) + long_name: peck (İngiliz) + symbols: + - pk + L84: + name: Nakliye tonu (Br.) + long_name: ton (Birleşik Krallık nakliye) + symbols: + - Shipping ton (Br.) + L86: + name: Nakliye tonu (Am.) + long_name: ton (ABD nakliye) + symbols: + - Shipping ton (Am.) + OZA: + name: Sıvı ons + long_name: Sıvı ons (Amerikan) + symbols: + - fl oz + BUI: + name: Buşel (Br.) + long_name: Bushel (İngiliz) + symbols: + - bushel + BUA: + name: Bushel (Am.) + long_name: Bushel (Amerikan) + symbols: + - bu + BLL: + name: Varil (Am.) + long_name: Varil (Amerikan) + symbols: + - barrel + BLD: + name: Kuru Fıçı (Am.) + long_name: Dry Barrel (Amerikan) + symbols: + - bbl + GLD: + name: Kuru Galon (Am.) + long_name: Kuru Galon (Amerikan) + symbols: + - dry gal + QTD: + name: Kuru Quart (Am.) + long_name: Dry Quart (Amerikan) + symbols: + - dry qt + G26: + name: Ster + long_name: Ster (dökme metreküp) + symbols: + - st + G21: + name: Fincan + long_name: Cup [hacim birimi] + symbols: + - cup + G24: + name: Yemek Kaşığı + long_name: Yemek Kaşığı + symbols: + - yk + G25: + name: Çay Kaşığı + long_name: Çay Kaşığı + symbols: + - çk + G23: + name: Çeyrek kile (Am.) + long_name: Çeyrek kile (Amerikan) + symbols: + - pk + JOU: + name: Joule + long_name: Joule + symbols: + - J + J75: + name: Kalori + long_name: Kalori + symbols: + - cal + K51: + name: Kilokalori + long_name: Kilokalori + symbols: + - kcal + J55: + name: Watt saniye + long_name: Watt saniye + symbols: + - Ws + WHR: + name: Watt saat + long_name: Watt saat + symbols: + - Wh + KWH: + name: Kilowatt saat + long_name: Kilowatt saat + symbols: + - kWh + GWH: + name: Gigawatt saat + long_name: Gigawatt saat + symbols: + - GWh + WTT: + name: Watts + long_name: Watts + symbols: + - W + KWT: + name: Kilowatt + long_name: Kilowatt + symbols: + - kW + MAW: + name: Megawatt + long_name: Megawatt + symbols: + - MW diff --git a/config/units-of-measure/translations_piece.csv b/config/units-of-measure/translations_piece.csv new file mode 100644 index 000000000..d4df81de4 --- /dev/null +++ b/config/units-of-measure/translations_piece.csv @@ -0,0 +1,69 @@ +Common code,Original name,English suggestion,Engl. abbr.,Engl. Aliases,German suggestion,German abbr.,German aliases,Description +XCU,Cup,Cup,,,Becher,,, +XCN,"Container, not otherwise specified as transport equipment",Container,,,Behälter,,, +XSH,Sachet ,Sachet ,,,Beutel,,, +X43,"Bag, super bulk",Big bag,,,Bigbag,,,A cloth plastic or paper based bag having the dimensions of the pallet on which it is constructed. +XST,Sheet,Sheet,,,Blatt,Bl.,, +XOK,Block,Block,,,Block,,,"A solid piece of a hard substance, such as granite, having one or more flat sides." +XVA,Vat,Vat,,,Bottich,,, +XBX,Box,Box,,,Box,,, +XBH,Bunch,Bunch,,,Bund,Bd.,bd, +XBE,Bundle ,Bundle ,bdl.,,Bündel ,Bdl.,, +XCX,"Can, cylindrical ",Can,,,Dose,,, +XBJ,Bucket ,Bucket ,,,Eimer ,,, +XUN,Unit,Unit,,,Einheit,,,"A type of package composed of a single item or object, not otherwise specified as a unit of transport equipment." +XOS,Oneway pallet,Oneway pallet,,,Einweg-Palette,,,Pallet need not be returned to the point of expedition +XDH,"Box, Commonwealth Handling Equipment Pool (CHEP), Eurobox","Eurobox, CHEP box",box,,"Eurobox, CHEP-Box",Box,,A box mounted on a pallet base under the control of CHEP. +XBA,Barrel ,Barrel ,,,Fass,,, +XFI,Firkin ,Firkin ,,,Fässchen ,,, +XBO,"Bottle, non-protected, cylindrical ",Bottle,btl.,btl,Flasche,Fl.,fl,A narrow-necked cylindrical shaped vessel without external protective packing material. +XBQ,"Bottle, protected cylindrical",Protected bottle,btl.,,Flasche in Umverpackung,Fl.,,A narrow-necked cylindrical shaped vessel with external protective packing material. +XFB,Flexibag,Flexibag,,,Flexibag,,,"A flexible containment bag made of plastic, typically for the transportation bulk non-hazardous cargoes using standard size shipping containers." +XFT,Foodtainer,Foodtainer,,,Foodtainer,,, +XJR,Jar,Jar,,,Glas,Gl.,gl, +XGR,"Receptacle, glass ",Glass receptacle,,,Glasgefäß,,,Containment vessel made of glass for retaining substances or articles. +XOW,"Large bag, pallet sized",Pallet sized large bag,,,Großer Sack in Palettengröße,,,"A non-rigid container made of fabric, paper, plastic, etc, with an opening at the top which can be closed and which is suitable for use on pallets" +X8B,"Crate, wooden",Wooden crate,,,Holzkiste,,,"A receptacle, made of wood, on which goods are retained for ease of mechanical handling during transport and storage." +XCV,Cover,Cover,,,Hülle,,, +XWA,Intermediate bulk container,Intermediate bulk container (IBC),IBC,,Intermediate Bulk Container (IBC),IBC,,"A reusable container made of metal, plastic, textile, wood or composite materials used to facilitate transportation of bulk solids and liquids in manageable volumes." +XEI,"Case, isothermic ",Isothermic case,,,Isotherme Box,,, +XJT,Jutebag,Jutebag,,,Jutebeutel,,, +XGY,"Bag, gunny",Gunny bag,,,Jutesack,,,"A sack made of gunny or burlap, used for transporting coarse commodities, such as grains, potatoes, and other agricultural products. " +XJY,"Jerrican, cylindrical",Jerrican,,,Kanister,,, +XBD,Board,Board,,,Karton,,, +XCR,Crate,Crate,,,Kiste,,, +XAI,Clamshell,Clamshell,,,Klappverpackung,,, +XPA,Packet ,Packet ,,,Kollo,,,Small package. +XBK,Basket ,Basket ,,,Korb ,,, +XBI,Bin,Bin,,,Kübel,,, +XOV,Returnable pallet,Returnable pallet,,,Mehrwegpalette,,,Pallet must be returned to the point of expedition. +XNT,Net,Net,,,Netz,,, +XPK,Package,Package,pkg.,pkg,Packung,Pkg.,"pkg, pkt",Standard packaging unit. +XPC,Parcel ,Parcel ,,,Paket ,,, +XPX,Pallet ,Pallet ,,,Palette ,,,"Platform or open-ended box, usually made of wood, on which goods are retained for ease of mechanical handling during transport and storage." +X5M,"Bag, paper ",Paper bag,,,Papiertüte,,, +XPR,"Receptacle, plastic ",Plastic receptacle,,,Plastikgefäß,,,Containment vessel made of plastic for retaining substances or articles. +XEC,"Bag, plastic ",Plastic bag,,,Plastiktüte,,, +X6H,"Composite packaging, plastic receptacle",Plastic composite packaging,,,Plastik-Verbundverpackung,,, +X44,"Bag, polybag",Polybag,,,Polybeutel,,,"A type of plastic bag, typically used to wrap promotional pieces, publications, product samples, and/or catalogues. " +XBR,Bar,Bar,,,Riegel,,, +XCW,"Cage, roll ",Roll cage,,,Rollcontainer,,, +XBT,Bolt ,Bolt ,,,Rolle,,, +XSA,Sack ,Sack ,,,Sack ,,, +XBM,Basin,Bowl,,,Schüssel,,, +XSX,Set,Set,,,Set,,, +XDN,Dispenser,Dispenser,,,Spender,,, +XAE,Aerosol,Aerosol,,,Sprühdose,,, +XSC,"Crate, shallow ",Shallow crate,,,Steige,,, +XLU,Lug,Lug,,,Stiege,,,A wooden box for the transportation and storage of fruit or vegetables. +X5L,"Bag, textile ",Textile bag,,,Stofftüte,,, +XPP,Piece,Piece,,pc,Stück,,"stk, st, stueck",A loose or unpacked article. +XPU,Tray ,Tray ,,,Schale,,, +XBG,Bag,Bag,,,Tasche,,,A receptacle made of flexible material with an open or closed top. +XP2,Pan,Pan,,,Tiegel,,,"A shallow, wide, open container, usually of metal." +XCK,Cask ,Cask ,,,Tonne,,, +XPT,Pot,Pot,,,Topf,,tiegel, +XGI,Girder ,Girder ,,,Träger ,,, +XTU,Tube ,Tube ,,,Tube,,, +PTN,Portion,Portion,,,Portion,,port, +STC,Sick,Stick,,,Stange,,, diff --git a/config/units-of-measure/translations_scalar-de.csv b/config/units-of-measure/translations_scalar-de.csv new file mode 100644 index 000000000..37730e913 --- /dev/null +++ b/config/units-of-measure/translations_scalar-de.csv @@ -0,0 +1,120 @@ +common code,full name,short name,symbol,alt. Symbols,aliases,description +DMT,Dezimeter,Dezimeter,dm,,, +CMT,Zentimeter,Zentimeter,cm,,, +4H,Mikrometer (Mikron),Mikrometer,µm,,, +MMT,Millimeter,Millimeter,mm,,, +HMT,Hektometer,Hektometer,hm,,, +KMT,Kilometer,Kilometer,km,,, +A45,Dekameter,Dekameter,dam,,, +INH,Zoll,Zoll,″,in,, +FOT,Fuß,Fuß,ft,,, +YRD,Yard,Yard,yd,,, +SMI,Meile (britisch),Meile,mile,,, +77,Millizoll,Millizoll,mil,,, +MTK,Quadratmeter,Quadratmeter,m²,qm,, +DAA,Dekar,Dekar,daa,,, +KMK,Quadratkilometer,Quadratkilometer,km²,,, +CMK,Quadratzentimeter,Quadratzentimeter,cm²,,, +DMK,Quadratdezimeter,Quadratdezimeter,dm²,,, +H16,Quadratdekameter,Quadratdekameter,dam²,,,Synonym: Ar +H18,Quadrathektometer,Quadrathektometer,hm²,,,Synonym: Hektar +MMK,Quadratmillimeter,Quadratmillimeter,mm²,,, +M47,Circular mil ,Circular mil ,cmil,,,"Unit of an area, of which the size is given by a diameter of length of 1 mm (0,001 in) based on the formula: area = p·(diameter/2)²." +ARE,Ar,Ar,a,,,Synonym: Quadratdekameter +HAR,Hektar,Hektar,ha,,,Synonym: Quadrathektometer +INK,Quadratzoll,Quadratzoll,in²,,, +FTK,Quadratfuß,Quadratfuß,ft²,,, +YDK,Quadratmeter,Quadratmeter,yd²,,, +MIK,Quadratmeile (britisch),Quadratmeile,mi²,,, +ACR,Morgen,Morgen,acre,,, +KGM,Kilogramm,Kilogramm,kg,,kilo, +HGM,Hektogramm,Hektogramm,hg,,, +KTN,Kilotonne,Kilotonne,kt,,, +DJ,Dekagramm,Dekagramm,dag,dkg,, +DG,Dezigramm,Dezigramm,dg,,, +CGM,Zentigramm,Zentigramm,cg,,, +DTN,Dezitonne,Dezitonne,dt,dtn,,"Synonym: Zentner (A, CH)" +MGM,Milligramm,Milligramm,mg,,, +2U,Megagramm,Megagramm,Mg,,, +MC,Mikrogramm,Mikrogramm,µg,,, +GRM,Gramm,Gramm,g,,"gr, grm", +TNE,Tonne (metrisch),Tonne,t,,, +M86,Pfund,Pfund,pfd,,,Veraltete deutsche Masseeinheit +LBR,Englisches Pfund,Englisches Pfund,lb,,, +GRN,Gran,Gran,gr,,, +ONZ,Unze (avoirdupois),Unze,oz,,, +CWI,Hundredweight (britisch),Br. Zentner,cwt,,, +CWA,Hundredweight (amerikanisch),Am. Zentner,cwt,,, +LTN,"Britische Tonne, Long Ton (amerikanisch)",Br. Tonne,ton (Br.),,,Synonym: gross ton (2240 lb) +STI,Stein (britisch),Stein,st,,, +STN,"Amerikanische Tonne, Short Ton",Am. Tonne,ton (Am.),,,Synonym: net ton (2000 lb) +APZ,Feinunze oder Apothekerunze,Feinunze,tr oz,,, +F13,Slug,Slug,slug,,,A unit of mass. One slug is the mass accelerated at 1 foot per second per second by a force of 1 pound. +SEC,Sekunde [Zeiteinheit],Sekunde,s,,, +MIN,Minute [Zeiteinheit],Minute,min,,, +HUR,Stunde,Stunde,h,,, +DAY,Tag,Tag,d,,, +C26,Millisekunde,Millisekunde,ms,,, +WEE,Woche,Woche,wk,,, +MON,Monat,Monat,mo,,,"Zeiteinheit gleich 1/12 eines Jahres oder 365,25 Tage." +ANN,Jahr,Jahr,y,,,"Zeiteinheit gleich 365,25 Tage (Julianisches Jahr)" +MTQ,Kubikmeter,Kubikmeter,m³,cbm,, +LTR,Liter,Liter,l,,, +MAL,Megaliter,Megaliter,Ml,,, +DLT,Deziliter,Deziliter,dl,,, +4G,Mikroliter,Mikroliter,µl,,, +K6,Kiloliter,Kiloliter,kl,,, +A44,Dekaliter,Dekaliter,dal,,, +MMQ,Kubikmillimeter,Kubikmillimeter,mm³,,, +CMQ,Kubikzentimeter,Kubikzentimeter,cm³,ccm,, +DMQ,Kubikdezimeter,Kubikdezimeter,dm³,,, +MLT,Milliliter,Milliliter,ml,,, +HLT,Hektoliter,Hektoliter,hl,,, +CLT,Zentiliter,Zentiliter,cl,,, +DMA,Kubikdekameter,Kubikdekameter,dam³,,, +H19,Kubikhektometer,Kubikhektometer,hm³,,, +H20,Kubikkilometer,Kubikkilometer,km³,,, +M67,acre-foot (basierend auf U.S. Survey Foot),acre-foot,acre-ft,,,"Unit of the volume, which is Am.ed in the United States to measure/gauge the capacity of reservoirs." +M68,Cord (128 ft3),Cord,cord,,,Traditional unit of the volume of stacked firewood which has been measured with a cord. +M69,Kubikmeile (britisch),Kubikmeile,mi³,,,Unit of volume according to the Imperial system of units. +M70,Registertonne,Registertonne,RT,,,Traditional unit of the cargo capacity. +5I,Kubikfuß,Kubikfuß,std,,, +INQ,Kubikzoll,Kubikzoll,in³,,, +FTQ,Kubikfuß,Kubikfuß,ft³,,, +YDQ,Kubikmeter,Kubikmeter,yd³,,, +GLI,Gallone (britisch),Gallone (Br.),gal,,, +GLL,Gallone (amerikanisch),Gallone (Am.),gal,,, +PTI,Pint (britisch),Pint (Br.),pt,,, +QTI,quart (britisch),Quart,qt,,, +PTL,flüssiges Pint (amerikanisch),flüssiges Pint (Am.),liq pt,,, +QTL,flüssiges Quart (amerikanisch),flüssiges Quart (Am.),liq qt,,, +PTD,trockenes Pint (amerikanisch),trockenes Pint (Am.),dry pt,,, +OZI,flüssige Unze (britisch),flüssige Unze (Br.),fl oz,,, +J57,Barrel (britisch),Barrel (Br.),bbl,,, +L43,peck (britisch),Viertelscheffel (Br.),pk,,, +L84,ton (UK shipping),Shipping ton (Br.),Shipping ton (Br.),,, +L86,ton (US shipping),Shipping ton (Am.),Shipping ton (Am.),,, +OZA,Flüssigunze (amerikanisch),Flüssigunze,fl oz,,, +BUI,Scheffel (britisch),Scheffel (Br.),bushel,,, +BUA,Scheffel (amerikanisch),Scheffel (Am.),bu,,, +BLL,Barrel (amerikanisch),Barrel (Am.),barrel,,, +BLD,Dry Barrel (amerikanisch),Dry Barrel (Am.),bbl,,, +GLD,Dry Gallon (amerikanisch),Dry Gallon (Am.),dry gal,,, +QTD,Dry Quart (amerikanisch),Dry Quart (Am.),dry qt,,, +G26,Ster (Schüttraummeter),Ster,st,,,Kubikmeter +G21,Tasse [Volumeneinheit],Tasse,cup,,, +G24,Esslöffel,Esslöffel,EL,,, +G25,Teelöffel,Teelöffel,TL,,, +G23,Viertelscheffel (amerikanisch),Viertelscheffel (Am.),pk,,, +JOU,Joule,Joule,J,,, +J75,Kalorie,Kalorie,cal,,, +K51,Kilokalorie,Kilokalorie,kcal,,, +J55,Wattsekunde,Wattsekunde,Ws,,, +WHR,Wattstunde,Wattstunde,Wh,,, +KWH,Kilowattstunde,Kilowattstunde,kWh,,, +GWH,Gigawattstunde,Gigawattstunde,GWh,,, +WTT,Watt,Watt,W,,, +KWT,Kilowatt,Kilowatt,kW,,, +MAW,Megawatt,Megawatt,MW,,,A unit of power defining the rate of energy transferred or consumed when a current of 1000 amperes flows due to a potential of 1000 volts at unity power factor. +PTN,Portion,Portion,,,, +STC,Stange,Stange,,,, diff --git a/config/units-of-measure/translations_scalar-en.csv b/config/units-of-measure/translations_scalar-en.csv new file mode 100644 index 000000000..3c4baae87 --- /dev/null +++ b/config/units-of-measure/translations_scalar-en.csv @@ -0,0 +1,121 @@ +common code,full name,short name,symbol,alt. Symbols,aliases,description +DMT,decimetre,decimetre,dm,,, +CMT,centimetre,centimetre,cm,,, +4H,micrometre (micron),micrometre,µm,,, +MMT,millimetre,millimetre,mm,,, +HMT,hectometre,hectometre,hm,,, +KMT,kilometre,kilometre,km,,, +A45,decametre,decametre,dam,,, +INH,inch,inch,in,,, +FOT,foot,foot,ft,,, +YRD,yard,yard,yd,,, +SMI,mile (statute mile),mile,mile,,, +77,milli-inch,milli-inch,mil,,, +MTK,square metre,square metre,m²,sq m,, +DAA,decare,decare,daa,,, +KMK,square kilometre,square kilometre,km²,sq km,, +CMK,square centimetre,square centimetre,cm²,sq cm,, +DMK,square decimetre,square decimetre,dm²,sq dm,, +H16,square decametre,square decametre,dam²,sq dam,,Synonym: are +H18,square hectometre,square hectometre,hm²,sq hm,,Synonym: hectare +MMK,square millimetre,square millimetre,mm²,sq mm,, +M47,circular mil ,circular mil ,cmil,,,"Unit of an area, of which the size is given by a diameter of length of 1 mm (0,001 in) based on the formula: area = p·(diameter/2)²." +ARE,are,are,a,,,Synonym: square decametre +HAR,hectare,hectare,ha,,,Synonym: square hectometre +INK,square inch,square inch,in²,sq in,, +FTK,square foot,square foot,ft²,sq ft,, +YDK,square yard,square yard,yd²,sq yd,, +MIK,square mile (statute mile),square mile,mi²,sq mi,, +ACR,acre,acre,acre,,, +KGM,kilogram,kilogram,kg,,kilo,A unit of mass equal to one thousand grams. +HGM,hectogram,hectogram,hg,,, +KTN,kilotonne,kilotonne,kt,,, +DJ,decagram,decagram,dag,dkg,, +DG,decigram,decigram,dg,,, +CGM,centigram,centigram,cg,,, +DTN,decitonne,decitonne,dt,dtn,,"Synonym: centner, metric 100 kg; quintal, metric 100 kg" +MGM,milligram,milligram,mg,,, +2U,megagram,megagram,Mg,,, +MC,microgram,microgram,µg,,, +GRM,gram,gram,g,,"gr, grm", +TNE,tonne (metric),metric ton,t,mt,, +M86,pfund,pfund,pfd,,,Outdated unit of the mass used in Germany. +LBR,pound,pound,lb,,, +GRN,grain,grain,gr,,, +ONZ,ounce (avoirdupois),ounce,oz,,, +CWI,hundred weight (UK),hundred weight,cwt,,, +CWA,hundred pound (cwt) / hundred weight (US),hundred pound (cwt) / hundred weight (US),cwt,,, +LTN,ton (UK) or long ton (US),ton (UK) or long ton (US),ton (UK),,,Synonym: gross ton (2240 lb) +STI,stone (UK),stone,st,,, +STN,ton (US) or short ton (UK/US),ton (US) or short ton (UK/US),ton (US),,,Synonym: net ton (2000 lb) +APZ,troy ounce or apothecary ounce,troy ounce,tr oz,,, +F13,slug,slug,slug,,,A unit of mass. One slug is the mass accelerated at 1 foot per second per second by a force of 1 pound. +SEC,second [unit of time],second,s,,, +MIN,minute [unit of time],minute,min,,, +HUR,hour,hour,h,,, +DAY,day,day,d,,, +C26,millisecond,millisecond,ms,,, +WEE,week,week,wk,,, +MON,month,month,mo,,,"Unit of time equal to 1/12 of a year of 365,25 days." +ANN,year,year,y,,,"Unit of time equal to 365,25 days. +Synonym: Julian year" +MTQ,cubic metre,cubic metre,m³,,,Synonym: metre cubed +LTR,litre,litre,l,,, +MAL,megalitre,megalitre,Ml,,, +DLT,decilitre,decilitre,dl,,, +4G,microlitre,microlitre,µl,,, +K6,kilolitre,kilolitre,kl,,, +A44,decalitre,decalitre,dal,,, +MMQ,cubic millimetre,cubic millimetre,mm³,,, +CMQ,cubic centimetre,cubic centimetre,cm³,"cc, ccm",, +DMQ,cubic decimetre,cubic decimetre,dm³,,, +MLT,millilitre,millilitre,ml,,, +HLT,hectolitre,hectolitre,hl,,, +CLT,centilitre,centilitre,cl,,, +DMA,cubic decametre,cubic decametre,dam³,,, +H19,cubic hectometre,cubic hectometre,hm³,,, +H20,cubic kilometre,cubic kilometre,km³,,, +M67,acre-foot (based on U.S. survey foot),acre-foot,acre-ft,,,"Unit of the volume, which is used in the United States to measure/gauge the capacity of reservoirs." +M68,cord (128 ft3),cord,cord,,,Traditional unit of the volume of stacked firewood which has been measured with a cord. +M69,cubic mile (UK statute),cubic mile,mi³,,,Unit of volume according to the Imperial system of units. +M70,register ton,register ton,RT,,,Traditional unit of the cargo capacity. +5I,standard cubic foot,standard cubic foot,std,,,Use standard (common code WSD) +INQ,cubic inch,cubic inch,in³,,,Synonym: inch cubed +FTQ,cubic foot,cubic foot,ft³,,, +YDQ,cubic yard,cubic yard,yd³,,, +GLI,gallon (UK),gallon (UK),gal,,, +GLL,gallon (US),gallon (US),gal,,, +PTI,pint (UK),pint (UK),pt,,, +QTI,quart (UK),quart (UK),qt,,, +PTL,liquid pint (US),liquid pint (US),liq pt,,, +QTL,liquid quart (US),liquid quart (US),liq qt,,, +PTD,dry pint (US),dry pint (US),dry pt,,, +OZI,fluid ounce (UK),fluid ounce (UK),fl oz,,, +J57,barrel (UK petroleum),barrel (UK petroleum),bbl,,, +L43,peck (UK),peck (UK),pk (UK),,, +L84,ton (UK shipping),ton (UK shipping),British shipping ton,,, +L86,ton (US shipping),ton (US shipping),(US) shipping ton,,, +OZA,fluid ounce (US),fluid ounce (US),fl oz,,, +BUI,bushel (UK),bushel (UK),bushel,,, +BUA,bushel (US),bushel (US),bu,,, +BLL,barrel (US),barrel (US),barrel,,, +BLD,dry barrel (US),dry barrel (US),bbl,,, +GLD,dry gallon (US),dry gallon (US),dry gal,,, +QTD,dry quart (US),dry quart (US),dry qt,,, +G26,stere,stere,st,,,cubic metre +G21,cup [unit of volume],cup,cup,,, +G24,tablespoon (US),tablespoon,tbsp.,,, +G25,teaspoon (US),teaspoon,tsp.,,, +G23,peck (US),peck (US),pk (US),,, +JOU,joule,joule,J,,, +J75,calorie (mean),calorie,cal,,, +K51,kilocalorie (mean),kilocalorie,kcal,,, +J55,watt second,watt second,Ws,,, +WHR,watt hour,watt hour,Wh,,, +KWH,kilowatt hour,kilowatt hour,kWh,,, +GWH,gigawatt hour,gigawatt hour,GWh,,, +WTT,watt,watt,W,,, +KWT,kilowatt,kilowatt,kW,,, +MAW,megawatt,megawatt,MW,,,A unit of power defining the rate of energy transferred or consumed when a current of 1000 amperes flows due to a potential of 1000 volts at unity power factor. +PTN,portion,portion,,,, +STC,stick,stick,,,, diff --git a/config/units-of-measure/un-ece-20-remastered.yml b/config/units-of-measure/un-ece-20-remastered.yml new file mode 100644 index 000000000..d6e484d01 --- /dev/null +++ b/config/units-of-measure/un-ece-20-remastered.yml @@ -0,0 +1,22825 @@ +# This file has been autogenerated by `rake units:clean_unece20_source` +--- +- Status: X + LevelAndCategory: '3.9' + Name: lift + ConversionFactor: '' + Symbol: '' + CommonCode: '05' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: small spray + ConversionFactor: '' + Symbol: '' + CommonCode: '06' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: heat lot + ConversionFactor: '' + Symbol: '' + CommonCode: '08' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: group + ConversionFactor: '' + Symbol: '' + CommonCode: '10' + Description: 'A unit of count defining the number of groups (group: set of items + classified together).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: outfit + ConversionFactor: '' + Symbol: '' + CommonCode: '11' + Description: 'A unit of count defining the number of outfits (outfit: a complete + set of equipment / materials / objects used for a specific purpose).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: ration + ConversionFactor: '' + Symbol: '' + CommonCode: '13' + Description: 'A unit of count defining the number of rations (ration: a single portion + of provisions).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: shot + ConversionFactor: '' + Symbol: '' + CommonCode: '14' + Description: A unit of liquid measure, especially related to spirits. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: stick, military + ConversionFactor: '' + Symbol: '' + CommonCode: '15' + Description: 'A unit of count defining the number of military sticks (military stick: + bombs or paratroops released in rapid succession from an aircraft).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: hundred fifteen kg drum + ConversionFactor: '' + Symbol: '' + CommonCode: '16' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: hundred lb drum + ConversionFactor: '' + Symbol: '' + CommonCode: '17' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: fiftyfive gallon (US) drum + ConversionFactor: '' + Symbol: '' + CommonCode: '18' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: tank truck + ConversionFactor: '' + Symbol: '' + CommonCode: '19' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: twenty foot container + ConversionFactor: '' + Symbol: '' + CommonCode: '20' + Description: A unit of count defining the number of shipping containers that measure + 20 foot in length. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: forty foot container + ConversionFactor: '' + Symbol: '' + CommonCode: '21' + Description: A unit of count defining the number of shipping containers that measure + 40 foot in length. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: decilitre per gram + ConversionFactor: 10⁻¹ x m³/kg + Symbol: dl/g + CommonCode: '22' + Description: '' + conversion: + factor: 0.1 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gram per cubic centimetre + ConversionFactor: 10³ kg/m³ + Symbol: g/cm³ + CommonCode: '23' + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '3.1' + Name: theoretical pound + ConversionFactor: '' + Symbol: '' + CommonCode: '24' + Description: A unit of mass defining the expected mass of material expressed as + the number of pounds. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: gram per square centimetre + ConversionFactor: 10 kg/m² + Symbol: g/cm² + CommonCode: '25' + Description: '' + conversion: + factor: 10.0 + base_units: + - '28' +- Status: X + LevelAndCategory: '3.1' + Name: actual ton + ConversionFactor: '' + Symbol: '' + CommonCode: '26' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: theoretical ton + ConversionFactor: '' + Symbol: '' + CommonCode: '27' + Description: A unit of mass defining the expected mass of material, expressed as + the number of tons. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: kilogram per square metre + ConversionFactor: kg/m² + Symbol: kg/m² + CommonCode: '28' + Description: '' + conversion: + factor: 1.0 + base_units: + - '28' +- Status: X + LevelAndCategory: '3.8' + Name: pound per thousand square foot + ConversionFactor: '' + Symbol: lb/kft² + CommonCode: '29' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: horse power day per air dry metric ton + ConversionFactor: '' + Symbol: '' + CommonCode: '30' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: catch weight + ConversionFactor: '' + Symbol: '' + CommonCode: '31' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: kilogram per air dry metric ton + ConversionFactor: '' + Symbol: '' + CommonCode: '32' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kilopascal square metre per gram + ConversionFactor: 10⁶ m/s² + Symbol: kPa·m²/g + CommonCode: '33' + Description: '' + conversion: + factor: 1000000.0 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: 1M + Name: kilopascal per millimetre + ConversionFactor: 10⁶ kg/(m² x s²) + Symbol: kPa/mm + CommonCode: '34' + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per square centimetre second + ConversionFactor: 10⁻² m/s + Symbol: ml/(cm²·s) + CommonCode: '35' + Description: '' + conversion: + factor: 0.01 + base_units: + - MTS + - P87 +- Status: X + LevelAndCategory: 1M + Name: cubic foot per minute per square foot + ConversionFactor: '' + Symbol: ft³/(min/ft²) + CommonCode: '36' + Description: Conversion factor required + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: ounce per square foot + ConversionFactor: 0,305 151 7 kg/m² + Symbol: oz/ft² + CommonCode: '37' + Description: '' + conversion: + factor: 0.3051517 + base_units: + - '28' +- Status: '' + LevelAndCategory: '3.9' + Name: ounce per square foot per 0,01inch + ConversionFactor: '' + Symbol: oz/(ft²/cin) + CommonCode: '38' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: millilitre per second + ConversionFactor: 10⁻⁶ m³/s + Symbol: ml/s + CommonCode: '40' + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1M + Name: millilitre per minute + ConversionFactor: 1,666 67 x 10⁻⁸ m³/s + Symbol: ml/min + CommonCode: '41' + Description: '' + conversion: + factor: 1.66667e-08 + base_units: + - MQS +- Status: X + LevelAndCategory: '3.3' + Name: super bulk bag + ConversionFactor: '' + Symbol: '' + CommonCode: '43' + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: fivehundred kg bulk bag + ConversionFactor: '' + Symbol: '' + CommonCode: '44' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: threehundred kg bulk bag + ConversionFactor: '' + Symbol: '' + CommonCode: '45' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: fifty lb bulk bag + ConversionFactor: '' + Symbol: '' + CommonCode: '46' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: fifty lb bag + ConversionFactor: '' + Symbol: '' + CommonCode: '47' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: bulk car load + ConversionFactor: '' + Symbol: '' + CommonCode: '48' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: theoretical kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: '53' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: theoretical tonne + ConversionFactor: '' + Symbol: '' + CommonCode: '54' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: sitas + ConversionFactor: '' + Symbol: '' + CommonCode: '56' + Description: A unit of area for tin plate equal to a surface area of 100 square + metres. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: mesh + ConversionFactor: '' + Symbol: '' + CommonCode: '57' + Description: A unit of count defining the number of strands per inch as a measure + of the fineness of a woven product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: net kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: '58' + Description: A unit of mass defining the total number of kilograms after deductions. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: part per million + ConversionFactor: 1 x 10⁻⁶ + Symbol: ppm + CommonCode: '59' + Description: A unit of proportion equal to 10⁻⁶. + conversion: + factor: 1.0e-06 +- Status: '' + LevelAndCategory: '3.7' + Name: percent weight + ConversionFactor: 1 x 10⁻² + Symbol: '' + CommonCode: '60' + Description: A unit of proportion equal to 10⁻². + conversion: + factor: 0.01 +- Status: '' + LevelAndCategory: '3.7' + Name: part per billion (US) + ConversionFactor: 1 x 10⁻⁹ + Symbol: ppb + CommonCode: '61' + Description: A unit of proportion equal to 10⁻⁹. + conversion: + factor: 1.0e-09 +- Status: X + LevelAndCategory: '3.7' + Name: percent per 1000 hour + ConversionFactor: '' + Symbol: '' + CommonCode: '62' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: failure rate in time + ConversionFactor: '' + Symbol: '' + CommonCode: '63' + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.1' + Name: pound per square inch, gauge + ConversionFactor: 7,030 696 x 10² kg/m² + Symbol: '' + CommonCode: '64' + Description: '' + conversion: + factor: 703.0696 + base_units: + - '28' +- Status: D + LevelAndCategory: '3.5' + Name: oersted + ConversionFactor: 7,957 747 x 10 A/m + Symbol: Oe + CommonCode: '66' + Description: '' + conversion: + factor: 7.957747 + base_units: + - AE +- Status: X + LevelAndCategory: '3.9' + Name: test specific scale + ConversionFactor: '' + Symbol: '' + CommonCode: '69' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: volt ampere per pound + ConversionFactor: '' + Symbol: '' + CommonCode: '71' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: watt per pound + ConversionFactor: '' + Symbol: '' + CommonCode: '72' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: ampere tum per centimetre + ConversionFactor: '' + Symbol: '' + CommonCode: '73' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millipascal + ConversionFactor: 10⁻³ Pa + Symbol: mPa + CommonCode: '74' + Description: '' + conversion: + factor: 0.001 + base_units: + - C55 + - PAL +- Status: D + LevelAndCategory: '3.5' + Name: gauss + ConversionFactor: 10⁻⁴ T + Symbol: Gs + CommonCode: '76' + Description: '' + conversion: + factor: 0.0001 + base_units: + - D33 +- Status: '' + LevelAndCategory: '2' + Name: milli-inch + ConversionFactor: 25,4 x 10⁻⁶ m + Symbol: mil + CommonCode: '77' + Description: '' + conversion: + factor: 2.54e-05 + base_units: + - MTR +- Status: D + LevelAndCategory: '3.5' + Name: kilogauss + ConversionFactor: 10⁻¹ T + Symbol: kGs + CommonCode: '78' + Description: '' + conversion: + factor: 0.1 + base_units: + - D33 +- Status: '' + LevelAndCategory: '2' + Name: pound per square inch absolute + ConversionFactor: 7,030 696 x 10² kg/m² + Symbol: lb/in² + CommonCode: '80' + Description: '' + conversion: + factor: 703.0696 + base_units: + - '28' +- Status: '' + LevelAndCategory: '1' + Name: henry + ConversionFactor: H + Symbol: H + CommonCode: '81' + Description: '' + conversion: + factor: 1.0 + base_units: + - '81' +- Status: D + LevelAndCategory: '2' + Name: kilopound-force per square inch + ConversionFactor: 6,894 757 x 10⁶ Pa + Symbol: klbf/in² + CommonCode: '84' + Description: A unit of pressure defining the number of kilopounds force per square + inch.,Use kip per square inch (common code N20). + conversion: + factor: 6894757.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: foot pound-force + ConversionFactor: 1,355 818 J + Symbol: ft·lbf + CommonCode: '85' + Description: '' + conversion: + factor: 1.355818 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: pound per cubic foot + ConversionFactor: 1,601 846 x 10¹ kg/m³ + Symbol: lb/ft³ + CommonCode: '87' + Description: '' + conversion: + factor: 16.01846 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: poise + ConversionFactor: 0,1 Pa x s + Symbol: P + CommonCode: '89' + Description: '' + conversion: + factor: 0.1 + base_units: + - C65 + - N36 + - N37 +- Status: X + LevelAndCategory: '3.9' + Name: Saybold universal second + ConversionFactor: '' + Symbol: '' + CommonCode: '90' + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: stokes + ConversionFactor: 10⁻⁴ m²/s + Symbol: St + CommonCode: '91' + Description: '' + conversion: + factor: 0.0001 + base_units: + - S4 +- Status: X + LevelAndCategory: '3.9' + Name: calorie per cubic centimetre + ConversionFactor: '' + Symbol: '' + CommonCode: '92' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: calorie per gram + ConversionFactor: 4,186 8 x 10³ J/kg + Symbol: cal/g + CommonCode: '93' + Description: Use International Table (IT) calorie per gram (common code D75). + conversion: + factor: 4186.8 + base_units: + - J2 +- Status: X + LevelAndCategory: '3.9' + Name: curl unit + ConversionFactor: '' + Symbol: '' + CommonCode: '94' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: twenty thousand gallon (US) tankcar + ConversionFactor: '' + Symbol: '' + CommonCode: '95' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: ten thousand gallon (US) tankcar + ConversionFactor: '' + Symbol: '' + CommonCode: '96' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: ten kg drum + ConversionFactor: '' + Symbol: '' + CommonCode: '97' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: fifteen kg drum + ConversionFactor: '' + Symbol: '' + CommonCode: '98' + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: car mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1A + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: car count + ConversionFactor: '' + Symbol: '' + CommonCode: 1B + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: locomotive count + ConversionFactor: '' + Symbol: '' + CommonCode: 1C + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: caboose count + ConversionFactor: '' + Symbol: '' + CommonCode: 1D + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: empty car + ConversionFactor: '' + Symbol: '' + CommonCode: 1E + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: train mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1F + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: fuel usage gallon (US) + ConversionFactor: '' + Symbol: '' + CommonCode: 1G + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: caboose mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1H + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: fixed rate + ConversionFactor: '' + Symbol: '' + CommonCode: 1I + Description: A unit of quantity expressed as a predetermined or set rate for usage + of a facility or service. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: ton mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1J + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: locomotive mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1K + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: total car count + ConversionFactor: '' + Symbol: '' + CommonCode: 1L + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: total car mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1M + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: quarter mile + ConversionFactor: '' + Symbol: '' + CommonCode: 1X + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: radian per second + ConversionFactor: rad/s + Symbol: rad/s + CommonCode: 2A + Description: Refer ISO/TC12 SI Guide + conversion: + factor: 1.0 + base_units: + - 2A +- Status: '' + LevelAndCategory: '1' + Name: radian per second squared + ConversionFactor: rad/s² + Symbol: rad/s² + CommonCode: 2B + Description: Refer ISO/TC12 SI Guide + conversion: + factor: 1.0 + base_units: + - 2B +- Status: '' + LevelAndCategory: '2' + Name: roentgen + ConversionFactor: 2,58 x 10⁻⁴ C/kg + Symbol: R + CommonCode: 2C + Description: '' + conversion: + factor: 0.000258 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: volt AC + ConversionFactor: V + Symbol: V + CommonCode: 2G + Description: A unit of electric potential in relation to alternating current (AC). + conversion: + factor: 1.0 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: '3.1' + Name: volt DC + ConversionFactor: V + Symbol: V + CommonCode: 2H + Description: A unit of electric potential in relation to direct current (DC). + conversion: + factor: 1.0 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per hour + ConversionFactor: 2,930 711x 10⁻¹ W + Symbol: BtuIT/h + CommonCode: 2I + Description: '' + conversion: + factor: 2.930711 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: cubic centimetre per second + ConversionFactor: 10⁻⁶ m³/s + Symbol: cm³/s + CommonCode: 2J + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic foot per hour + ConversionFactor: 7,865 79 x 10⁻⁶ m³/s + Symbol: ft³/h + CommonCode: 2K + Description: '' + conversion: + factor: 7.86579e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic foot per minute + ConversionFactor: 4,719 474 x 10⁻⁴ m³/s + Symbol: ft³/min + CommonCode: 2L + Description: '' + conversion: + factor: 0.0004719474 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1S + Name: centimetre per second + ConversionFactor: 10⁻² m/s + Symbol: cm/s + CommonCode: 2M + Description: '' + conversion: + factor: 0.01 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '1' + Name: decibel + ConversionFactor: 0,115 129 3 Np + Symbol: dB + CommonCode: 2N + Description: '' + conversion: + factor: 0.1151293 + base_units: + - C50 +- Status: '' + LevelAndCategory: '3.6' + Name: kilobyte + ConversionFactor: '' + Symbol: kbyte + CommonCode: 2P + Description: A unit of information equal to 10³ (1000) bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilobecquerel + ConversionFactor: 10³ Bq + Symbol: kBq + CommonCode: 2Q + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 2S + Name: kilocurie + ConversionFactor: 3,7 x 10¹³ Bq + Symbol: kCi + CommonCode: 2R + Description: '' + conversion: + factor: 37000000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: megagram + ConversionFactor: 10³ kg + Symbol: Mg + CommonCode: 2U + Description: '' + conversion: + factor: 1000.0 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.8' + Name: megagram per hour + ConversionFactor: '' + Symbol: Mg/h + CommonCode: 2V + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bin + ConversionFactor: '' + Symbol: '' + CommonCode: 2W + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: metre per minute + ConversionFactor: 0,016 666 m/s + Symbol: m/min + CommonCode: 2X + Description: '' + conversion: + factor: 0.016666 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: milliroentgen + ConversionFactor: 2,58 x 10⁻⁷ C/kg + Symbol: mR + CommonCode: 2Y + Description: '' + conversion: + factor: 2.58e-07 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: millivolt + ConversionFactor: 10⁻³ V + Symbol: mV + CommonCode: 2Z + Description: '' + conversion: + factor: 0.001 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: 1S + Name: megajoule + ConversionFactor: 10⁶ J + Symbol: MJ + CommonCode: 3B + Description: '' + conversion: + factor: 1000000.0 + base_units: + - JOU +- Status: '' + LevelAndCategory: '3.9' + Name: manmonth + ConversionFactor: '' + Symbol: '' + CommonCode: 3C + Description: A unit of count defining the number of months for a person or persons + to perform an undertaking. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: pound per pound of product + ConversionFactor: '' + Symbol: '' + CommonCode: 3E + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: pound per piece of product + ConversionFactor: '' + Symbol: '' + CommonCode: 3G + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: kilogram per kilogram of product + ConversionFactor: '' + Symbol: '' + CommonCode: 3H + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: kilogram per piece of product + ConversionFactor: '' + Symbol: '' + CommonCode: 3I + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bobbin + ConversionFactor: '' + Symbol: '' + CommonCode: 4A + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: cap + ConversionFactor: '' + Symbol: '' + CommonCode: 4B + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: centistokes + ConversionFactor: 10⁻⁶ m²/s + Symbol: cSt + CommonCode: 4C + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - S4 +- Status: X + LevelAndCategory: '3.2' + Name: twenty pack + ConversionFactor: '' + Symbol: '' + CommonCode: 4E + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: microlitre + ConversionFactor: 10⁻⁹ m³ + Symbol: µl + CommonCode: 4G + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: micrometre (micron) + ConversionFactor: 10⁻⁶ m + Symbol: µm + CommonCode: 4H + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1S + Name: milliampere + ConversionFactor: 10⁻³ A + Symbol: mA + CommonCode: 4K + Description: '' + conversion: + factor: 0.001 + base_units: + - AMP +- Status: '' + LevelAndCategory: '3.6' + Name: megabyte + ConversionFactor: '' + Symbol: Mbyte + CommonCode: 4L + Description: A unit of information equal to 10⁶ (1000000) bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: milligram per hour + ConversionFactor: 2,777 78 x 10⁻¹⁰ kg/s + Symbol: mg/h + CommonCode: 4M + Description: '' + conversion: + factor: 2.77778e-10 + base_units: + - KGS +- Status: '' + LevelAndCategory: 1S + Name: megabecquerel + ConversionFactor: 10⁶ Bq + Symbol: MBq + CommonCode: 4N + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: microfarad + ConversionFactor: 10⁻⁶ F + Symbol: µF + CommonCode: 4O + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - FAR +- Status: '' + LevelAndCategory: '1' + Name: newton per metre + ConversionFactor: N/m + Symbol: N/m + CommonCode: 4P + Description: '' + conversion: + factor: 1.0 + base_units: + - 4P +- Status: '' + LevelAndCategory: '2' + Name: ounce inch + ConversionFactor: 7,200 778 x 10⁻⁴ kg x m + Symbol: oz·in + CommonCode: 4Q + Description: '' + conversion: + factor: 0.0007200778 + base_units: + - M94 +- Status: '' + LevelAndCategory: '2' + Name: ounce foot + ConversionFactor: 8,640 934 x 10⁻³ kg x m + Symbol: oz·ft + CommonCode: 4R + Description: '' + conversion: + factor: 0.008640934 + base_units: + - M94 +- Status: '' + LevelAndCategory: 1S + Name: picofarad + ConversionFactor: 10⁻¹² F + Symbol: pF + CommonCode: 4T + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - FAR +- Status: '' + LevelAndCategory: '2' + Name: pound per hour + ConversionFactor: 1,259 979 x 10⁻⁴ kg/s + Symbol: lb/h + CommonCode: 4U + Description: '' + conversion: + factor: 0.0001259979 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ton (US) per hour + ConversionFactor: 2,519 958 x 10⁻¹ kg/s + Symbol: ton (US) /h + CommonCode: 4W + Description: '' + conversion: + factor: 0.2519958 + base_units: + - KGS +- Status: '' + LevelAndCategory: 1M + Name: kilolitre per hour + ConversionFactor: 2,777 78 x 10⁻⁴ m³/s + Symbol: kl/h + CommonCode: 4X + Description: '' + conversion: + factor: 0.000277778 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (US) per minute + ConversionFactor: 2,649 79 x 10⁻³ m³/s + Symbol: barrel (US)/min + CommonCode: 5A + Description: '' + conversion: + factor: 0.00264979 + base_units: + - MQS +- Status: '' + LevelAndCategory: '3.9' + Name: batch + ConversionFactor: '' + Symbol: '' + CommonCode: 5B + Description: 'A unit of count defining the number of batches (batch: quantity of + material produced in one operation or number of animals or persons coming at once).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: gallon(US) per thousand + ConversionFactor: '' + Symbol: '' + CommonCode: 5C + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: MMSCF/day + ConversionFactor: '' + Symbol: '' + CommonCode: 5E + Description: A unit of volume equal to one million (1000000) cubic feet of gas per + day. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: pound per thousand + ConversionFactor: '' + Symbol: '' + CommonCode: 5F + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: pump + ConversionFactor: '' + Symbol: '' + CommonCode: 5G + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: stage + ConversionFactor: '' + Symbol: '' + CommonCode: 5H + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '2' + Name: standard cubic foot + ConversionFactor: 4,672 m³ + Symbol: std + CommonCode: 5I + Description: Use standard (common code WSD) + conversion: + factor: 4.672 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.5' + Name: hydraulic horse power + ConversionFactor: '' + Symbol: '' + CommonCode: 5J + Description: A unit of power defining the hydraulic horse power delivered by a fluid + pump depending on the viscosity of the fluid. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: count per minute + ConversionFactor: '' + Symbol: '' + CommonCode: 5K + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: seismic level + ConversionFactor: '' + Symbol: '' + CommonCode: 5P + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: seismic line + ConversionFactor: '' + Symbol: '' + CommonCode: 5Q + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: 15 °C calorie + ConversionFactor: 4,188 46 J + Symbol: cal₁₅ + CommonCode: A1 + Description: '' + conversion: + factor: 4.18846 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: ampere square metre per joule second + ConversionFactor: "(A x s)/kg" + Symbol: A·m²/(J·s) + CommonCode: A10 + Description: '' + conversion: + factor: 1.0 + base_units: + - A10 +- Status: '' + LevelAndCategory: '1' + Name: angstrom + ConversionFactor: 10⁻¹⁰ m + Symbol: Å + CommonCode: A11 + Description: '' + conversion: + factor: 1.0e-10 + base_units: + - MTR +- Status: '' + LevelAndCategory: '1' + Name: astronomical unit + ConversionFactor: 1,495 978 70 x 10¹¹ m + Symbol: ua + CommonCode: A12 + Description: '' + conversion: + factor: 149597870000.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1S + Name: attojoule + ConversionFactor: 10⁻¹⁸ J + Symbol: aJ + CommonCode: A13 + Description: '' + conversion: + factor: 1.0e-18 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: barn + ConversionFactor: 10⁻²⁸ m² + Symbol: b + CommonCode: A14 + Description: '' + conversion: + factor: 1.0e-28 + base_units: + - MTK +- Status: '' + LevelAndCategory: '1' + Name: barn per electronvolt + ConversionFactor: 6,241 51 x 10⁻¹⁰ m²/J + Symbol: b/eV + CommonCode: A15 + Description: '' + conversion: + factor: 6.241 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: barn per steradian electronvolt + ConversionFactor: 6,241 51 x 10⁻¹⁰ m²/(sr xJ) + Symbol: b/(sr·eV) + CommonCode: A16 + Description: '' + conversion: + factor: 6.241 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: barn per steradian + ConversionFactor: 1 x 10⁻²⁸ m²/sr + Symbol: b/sr + CommonCode: A17 + Description: '' + conversion: + factor: 1.0e-28 + base_units: + - D24 +- Status: '' + LevelAndCategory: '1' + Name: becquerel per kilogram + ConversionFactor: 27,027 x 10⁻¹² Ci/kg + Symbol: Bq/kg + CommonCode: A18 + Description: '' + conversion: + factor: 2.7027e-11 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: becquerel per cubic metre + ConversionFactor: Bq/m³ + Symbol: Bq/m³ + CommonCode: A19 + Description: '' + conversion: + factor: 1.0 + base_units: + - A19 +- Status: '' + LevelAndCategory: 1S + Name: ampere per centimetre + ConversionFactor: 10² A/m + Symbol: A/cm + CommonCode: A2 + Description: '' + conversion: + factor: 100.0 + base_units: + - AE +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per second square foot degree Rankine + ConversionFactor: 20 441,7 W/(m² x K) + Symbol: BtuIT/(s·ft²·°R) + CommonCode: A20 + Description: '' + conversion: + factor: 20441.7 + base_units: + - D55 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per pound degree Rankine + ConversionFactor: 4 186,8 J/(kg x K) + Symbol: BtuIT/(lb·°R) + CommonCode: A21 + Description: '' + conversion: + factor: 4186.8 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per second foot degree Rankine + ConversionFactor: 6 230,64 W/(m x K) + Symbol: BtuIT/(s·ft·°R) + CommonCode: A22 + Description: '' + conversion: + factor: 6230.64 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per hour square foot degree Rankine + ConversionFactor: 5,678 26 W/ (m² x K) + Symbol: BtuIT/(h·ft²·°R) + CommonCode: A23 + Description: '' + conversion: + factor: 5.67826 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: candela per square metre + ConversionFactor: cd/m² + Symbol: cd/m² + CommonCode: A24 + Description: '' + conversion: + factor: 1.0 + base_units: + - A24 +- Status: D + LevelAndCategory: '2' + Name: cheval vapeur + ConversionFactor: 7,354 988 x 10² W + Symbol: CV + CommonCode: A25 + Description: 'Synonym: metric horse power' + conversion: + factor: 735.4988 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '1' + Name: coulomb metre + ConversionFactor: A x s x m + Symbol: C·m + CommonCode: A26 + Description: '' + conversion: + factor: 1.0 + base_units: + - A26 +- Status: '' + LevelAndCategory: '1' + Name: coulomb metre squared per volt + ConversionFactor: A² x s⁴/kg + Symbol: C·m²/V + CommonCode: A27 + Description: '' + conversion: + factor: 1.0 + base_units: + - A27 +- Status: '' + LevelAndCategory: 1S + Name: coulomb per cubic centimetre + ConversionFactor: 10⁶ C/m³ + Symbol: C/cm³ + CommonCode: A28 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A29 +- Status: '' + LevelAndCategory: '1' + Name: coulomb per cubic metre + ConversionFactor: C/m³ + Symbol: C/m³ + CommonCode: A29 + Description: '' + conversion: + factor: 1.0 + base_units: + - A29 +- Status: '' + LevelAndCategory: 1S + Name: ampere per millimetre + ConversionFactor: 10³ A/m + Symbol: A/mm + CommonCode: A3 + Description: '' + conversion: + factor: 1000.0 + base_units: + - AE +- Status: '' + LevelAndCategory: 1S + Name: coulomb per cubic millimetre + ConversionFactor: 10⁹ C/m³ + Symbol: C/mm³ + CommonCode: A30 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - A29 +- Status: '' + LevelAndCategory: '1' + Name: coulomb per kilogram second + ConversionFactor: A/kg + Symbol: C/(kg·s) + CommonCode: A31 + Description: '' + conversion: + factor: 1.0 + base_units: + - A31 +- Status: '' + LevelAndCategory: '1' + Name: coulomb per mole + ConversionFactor: A x s/mol + Symbol: C/mol + CommonCode: A32 + Description: '' + conversion: + factor: 1.0 + base_units: + - A32 +- Status: '' + LevelAndCategory: 1S + Name: coulomb per square centimetre + ConversionFactor: 10⁴ C/m² + Symbol: C/cm² + CommonCode: A33 + Description: '' + conversion: + factor: 10000.0 + base_units: + - A34 +- Status: '' + LevelAndCategory: '1' + Name: coulomb per square metre + ConversionFactor: C/m² + Symbol: C/m² + CommonCode: A34 + Description: '' + conversion: + factor: 1.0 + base_units: + - A34 +- Status: '' + LevelAndCategory: 1S + Name: coulomb per square millimetre + ConversionFactor: 10⁶ C/m² + Symbol: C/mm² + CommonCode: A35 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A34 +- Status: '' + LevelAndCategory: 1S + Name: cubic centimetre per mole + ConversionFactor: 10⁻⁶ m³/mol + Symbol: cm³/mol + CommonCode: A36 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A40 +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per mole + ConversionFactor: 10⁻³ m³/mol + Symbol: dm³/mol + CommonCode: A37 + Description: '' + conversion: + factor: 0.001 + base_units: + - A40 +- Status: '' + LevelAndCategory: '1' + Name: cubic metre per coulomb + ConversionFactor: m³/A x s + Symbol: m³/C + CommonCode: A38 + Description: '' + conversion: + factor: 1.0 + base_units: + - A38 +- Status: '' + LevelAndCategory: '1' + Name: cubic metre per kilogram + ConversionFactor: m³/kg + Symbol: m³/kg + CommonCode: A39 + Description: '' + conversion: + factor: 1.0 + base_units: + - A39 +- Status: '' + LevelAndCategory: 1S + Name: ampere per square centimetre + ConversionFactor: 10⁴ A/m² + Symbol: A/cm² + CommonCode: A4 + Description: '' + conversion: + factor: 10000.0 + base_units: + - A41 +- Status: '' + LevelAndCategory: '1' + Name: cubic metre per mole + ConversionFactor: m³/mol + Symbol: m³/mol + CommonCode: A40 + Description: '' + conversion: + factor: 1.0 + base_units: + - A40 +- Status: '' + LevelAndCategory: '1' + Name: ampere per square metre + ConversionFactor: A/m² + Symbol: A/m² + CommonCode: A41 + Description: '' + conversion: + factor: 1.0 + base_units: + - A41 +- Status: '' + LevelAndCategory: '2' + Name: curie per kilogram + ConversionFactor: 3,7 x 10¹⁰ Bq/kg + Symbol: Ci/kg + CommonCode: A42 + Description: '' + conversion: + factor: 37000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.4' + Name: deadweight tonnage + ConversionFactor: '' + Symbol: dwt + CommonCode: A43 + Description: A unit of mass defining the difference between the weight of a ship + when completely empty and its weight when completely loaded, expressed as the + number of tons. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: decalitre + ConversionFactor: 10⁻² m³ + Symbol: dal + CommonCode: A44 + Description: '' + conversion: + factor: 0.01 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: decametre + ConversionFactor: 10 m + Symbol: dam + CommonCode: A45 + Description: '' + conversion: + factor: 10.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.5' + Name: decitex + ConversionFactor: '' + Symbol: dtex (g/10km) + CommonCode: A47 + Description: A unit of yarn density. One decitex equals a mass of 1 gram per 10 + kilometres of length. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: degree Rankine + ConversionFactor: 5/9 x K + Symbol: "°R" + CommonCode: A48 + Description: 'Refer ISO 80000-5 (Quantities and units — Part 5: Thermodynamics)' + conversion: + factor: 5.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: denier + ConversionFactor: '' + Symbol: den (g/9 km) + CommonCode: A49 + Description: A unit of yarn density. One denier equals a mass of 1 gram per 9 kilometres + of length. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: ampere square metre + ConversionFactor: A x m² + Symbol: A·m² + CommonCode: A5 + Description: '' + conversion: + factor: 1.0 + base_units: + - A5 +- Status: D + LevelAndCategory: '2' + Name: dyne second per cubic centimetre + ConversionFactor: 10 Pa x s/m + Symbol: dyn·s/cm³ + CommonCode: A50 + Description: '' + conversion: + factor: 10.0 + base_units: + - C67 +- Status: D + LevelAndCategory: '2' + Name: dyne second per centimetre + ConversionFactor: 10⁻³ N x s/m + Symbol: dyn·s/cm + CommonCode: A51 + Description: '' + conversion: + factor: 0.001 + base_units: + - C58 +- Status: D + LevelAndCategory: '2' + Name: dyne second per centimetre to the fifth power + ConversionFactor: 10⁵ Pa x s/m³ + Symbol: dyn·s/cm⁵ + CommonCode: A52 + Description: '' + conversion: + factor: 100000.0 + base_units: + - C66 +- Status: '' + LevelAndCategory: '1' + Name: electronvolt + ConversionFactor: 1,602 176 487 x 10⁻¹⁹ J + Symbol: eV + CommonCode: A53 + Description: '' + conversion: + factor: 1.602176487e-19 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: electronvolt per metre + ConversionFactor: 1,602 176 487 x 10⁻¹⁹ J/m + Symbol: eV/m + CommonCode: A54 + Description: '' + conversion: + factor: 1.602176487e-19 + base_units: + - B12 +- Status: '' + LevelAndCategory: '1' + Name: electronvolt square metre + ConversionFactor: 1,602 176 487 x 10⁻¹⁹ J x m² + Symbol: eV·m² + CommonCode: A55 + Description: '' + conversion: + factor: 1.602176487e-19 + base_units: + - D73 +- Status: '' + LevelAndCategory: '1' + Name: electronvolt square metre per kilogram + ConversionFactor: 1,602 176 487 x 10⁻¹⁹ J x m²/kg + Symbol: eV·m²/kg + CommonCode: A56 + Description: '' + conversion: + factor: 1.602176487e-19 + base_units: + - B20 +- Status: D + LevelAndCategory: '2' + Name: erg + ConversionFactor: 10⁻⁷J + Symbol: erg + CommonCode: A57 + Description: '' + conversion: + factor: 1.0e-07 + base_units: + - JOU +- Status: D + LevelAndCategory: '2' + Name: erg per centimetre + ConversionFactor: 10⁻⁵ J/m + Symbol: erg/cm + CommonCode: A58 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - B12 +- Status: '' + LevelAndCategory: '3.9' + Name: 8-part cloud cover + ConversionFactor: '' + Symbol: '' + CommonCode: A59 + Description: 'A unit of count defining the number of eighth-parts as a measure of + the celestial dome cloud coverage.,Synonym: OKTA , OCTA' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: ampere per square metre kelvin squared + ConversionFactor: A/(m² x K²) + Symbol: A/(m²·K²) + CommonCode: A6 + Description: '' + conversion: + factor: 1.0 + base_units: + - A6 +- Status: D + LevelAndCategory: '2' + Name: erg per cubic centimetre + ConversionFactor: 10⁻¹ J/m³ + Symbol: erg/cm³ + CommonCode: A60 + Description: '' + conversion: + factor: 0.1 + base_units: + - B8 +- Status: D + LevelAndCategory: '2' + Name: erg per gram + ConversionFactor: 10⁻⁴ J/kg + Symbol: erg/g + CommonCode: A61 + Description: '' + conversion: + factor: 0.0001 + base_units: + - J2 +- Status: D + LevelAndCategory: '2' + Name: erg per gram second + ConversionFactor: 10⁻⁴ W/kg + Symbol: erg/g·s + CommonCode: A62 + Description: '' + conversion: + factor: 0.0001 + base_units: + - WA +- Status: D + LevelAndCategory: '2' + Name: erg per second + ConversionFactor: 10⁻⁷ W + Symbol: erg/s + CommonCode: A63 + Description: '' + conversion: + factor: 1.0e-07 + base_units: + - D46 + - P14 + - WTT +- Status: D + LevelAndCategory: '2' + Name: erg per second square centimetre + ConversionFactor: 10⁻³ W/m² + Symbol: erg/(s·cm²) + CommonCode: A64 + Description: '' + conversion: + factor: 0.001 + base_units: + - D54 +- Status: D + LevelAndCategory: '2' + Name: erg per square centimetre second + ConversionFactor: 10⁻³ W/m² + Symbol: erg/(cm²·s) + CommonCode: A65 + Description: '' + conversion: + factor: 0.001 + base_units: + - D54 +- Status: D + LevelAndCategory: '2' + Name: erg square centimetre + ConversionFactor: 10⁻¹¹ J x m² + Symbol: erg·cm² + CommonCode: A66 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - D73 +- Status: D + LevelAndCategory: '2' + Name: erg square centimetre per gram + ConversionFactor: 10⁻⁸ J x m²/kg + Symbol: erg·cm²/g + CommonCode: A67 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - B20 +- Status: '' + LevelAndCategory: 1S + Name: exajoule + ConversionFactor: 10¹⁸ J + Symbol: EJ + CommonCode: A68 + Description: '' + conversion: + factor: 1.0e+18 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: farad per metre + ConversionFactor: kg⁻¹ x m⁻³ x s⁴ x A² + Symbol: F/m + CommonCode: A69 + Description: '' + conversion: + factor: 1.0 + base_units: + - A69 +- Status: '' + LevelAndCategory: 1S + Name: ampere per square millimetre + ConversionFactor: 10⁶ A/m² + Symbol: A/mm² + CommonCode: A7 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A41 +- Status: '' + LevelAndCategory: 1S + Name: femtojoule + ConversionFactor: 10⁻¹⁵ J + Symbol: fJ + CommonCode: A70 + Description: '' + conversion: + factor: 1.0e-15 + base_units: + - JOU +- Status: '' + LevelAndCategory: 1S + Name: femtometre + ConversionFactor: 10⁻¹⁵ m + Symbol: fm + CommonCode: A71 + Description: '' + conversion: + factor: 1.0e-15 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: foot per second squared + ConversionFactor: 0,304 8 m/s² + Symbol: ft/s² + CommonCode: A73 + Description: '' + conversion: + factor: 0.3048 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '2' + Name: foot pound-force per second + ConversionFactor: 1,355 818 W + Symbol: ft·lbf/s + CommonCode: A74 + Description: '' + conversion: + factor: 1.355818 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.4' + Name: freight ton + ConversionFactor: '' + Symbol: '' + CommonCode: A75 + Description: A unit of information typically used for billing purposes, defined + as either the number of metric tons or the number of cubic metres, whichever is + the larger. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gal + ConversionFactor: 10⁻² m/s² + Symbol: Gal + CommonCode: A76 + Description: '' + conversion: + factor: 0.01 + base_units: + - MSK + - P79 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of displacement + ConversionFactor: '' + Symbol: '' + CommonCode: A77 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of electric current + ConversionFactor: '' + Symbol: '' + CommonCode: A78 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of electric charge + ConversionFactor: '' + Symbol: '' + CommonCode: A79 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: ampere second + ConversionFactor: C + Symbol: A·s + CommonCode: A8 + Description: '' + conversion: + factor: 1.0 + base_units: + - A8 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of electric field strength + ConversionFactor: '' + Symbol: '' + CommonCode: A80 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of electric polarization + ConversionFactor: '' + Symbol: '' + CommonCode: A81 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of electric potential + ConversionFactor: '' + Symbol: '' + CommonCode: A82 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: Gaussian CGS (Centimetre-Gram-Second system) unit of magnetization + ConversionFactor: '' + Symbol: '' + CommonCode: A83 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gigacoulomb per cubic metre + ConversionFactor: 10⁹ C/m³ + Symbol: GC/m³ + CommonCode: A84 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gigaelectronvolt + ConversionFactor: 10⁹ eV + Symbol: GeV + CommonCode: A85 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gigahertz + ConversionFactor: 10⁹ Hz + Symbol: GHz + CommonCode: A86 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gigaohm + ConversionFactor: 10⁹ Ω + Symbol: GΩ + CommonCode: A87 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gigaohm metre + ConversionFactor: 10⁹ Ω x m + Symbol: GΩ·m + CommonCode: A88 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: gigapascal + ConversionFactor: 10⁹ Pa + Symbol: GPa + CommonCode: A89 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.9' + Name: rate + ConversionFactor: '' + Symbol: '' + CommonCode: A9 + Description: A unit of quantity expressed as a rate for usage of a facility or service. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gigawatt + ConversionFactor: 10⁹ W + Symbol: GW + CommonCode: A90 + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: gon + ConversionFactor: 1,570 796 x 10⁻² rad + Symbol: gon + CommonCode: A91 + Description: 'Synonym: grade' + conversion: + factor: 0.01570796 + base_units: + - C81 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic metre + ConversionFactor: 10⁻³ kg/m³ + Symbol: g/m³ + CommonCode: A93 + Description: '' + conversion: + factor: 0.001 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1S + Name: gram per mole + ConversionFactor: 10⁻³ kg/mol + Symbol: g/mol + CommonCode: A94 + Description: '' + conversion: + factor: 0.001 + base_units: + - D74 +- Status: '' + LevelAndCategory: '1' + Name: gray + ConversionFactor: m²/s² + Symbol: Gy + CommonCode: A95 + Description: '' + conversion: + factor: 1.0 + base_units: + - A95 + - D13 +- Status: '' + LevelAndCategory: '1' + Name: gray per second + ConversionFactor: m²/s³ + Symbol: Gy/s + CommonCode: A96 + Description: '' + conversion: + factor: 1.0 + base_units: + - A96 +- Status: '' + LevelAndCategory: 1S + Name: hectopascal + ConversionFactor: 10² Pa + Symbol: hPa + CommonCode: A97 + Description: '' + conversion: + factor: 100.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '1' + Name: henry per metre + ConversionFactor: H/m + Symbol: H/m + CommonCode: A98 + Description: '' + conversion: + factor: 1.0 + base_units: + - A98 +- Status: '' + LevelAndCategory: '3.6' + Name: bit + ConversionFactor: '' + Symbol: bit + CommonCode: A99 + Description: A unit of information equal to one binary digit. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: ball + ConversionFactor: '' + Symbol: '' + CommonCode: AA + Description: 'A unit of count defining the number of balls (ball: object formed + in the shape of sphere).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: bulk pack + ConversionFactor: '' + Symbol: pk + CommonCode: AB + Description: A unit of count defining the number of items per bulk pack. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: acre + ConversionFactor: 4 046,873 m² + Symbol: acre + CommonCode: ACR + Description: '' + conversion: + factor: 4046.873 + base_units: + - MTK +- Status: '' + LevelAndCategory: '3.2' + Name: activity + ConversionFactor: '' + Symbol: '' + CommonCode: ACT + Description: 'A unit of count defining the number of activities (activity: a unit + of work or action).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: byte + ConversionFactor: '' + Symbol: byte + CommonCode: AD + Description: A unit of information equal to 8 bits. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: ampere per metre + ConversionFactor: A/m + Symbol: A/m + CommonCode: AE + Description: '' + conversion: + factor: 1.0 + base_units: + - AE +- Status: '' + LevelAndCategory: '3.5' + Name: additional minute + ConversionFactor: '' + Symbol: '' + CommonCode: AH + Description: A unit of time defining the number of minutes in addition to the referenced + minutes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: average minute per call + ConversionFactor: '' + Symbol: '' + CommonCode: AI + Description: A unit of count defining the number of minutes for the average interval + of a call. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: cop + ConversionFactor: '' + Symbol: '' + CommonCode: AJ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: fathom + ConversionFactor: 1,828 8 m + Symbol: fth + CommonCode: AK + Description: '' + conversion: + factor: 1.8288 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.5' + Name: access line + ConversionFactor: '' + Symbol: '' + CommonCode: AL + Description: A unit of count defining the number of telephone access lines. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: ampoule + ConversionFactor: '' + Symbol: '' + CommonCode: AM + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: ampere hour + ConversionFactor: 3,6 x 10³ C + Symbol: A·h + CommonCode: AMH + Description: A unit of electric charge defining the amount of charge accumulated + by a steady flow of one ampere for one hour. + conversion: + factor: 3600.0 + base_units: + - A8 +- Status: '' + LevelAndCategory: '1' + Name: ampere + ConversionFactor: A + Symbol: A + CommonCode: AMP + Description: '' + conversion: + factor: 1.0 + base_units: + - AMP +- Status: '' + LevelAndCategory: '2' + Name: year + ConversionFactor: 3,155 76 x 10⁷ s + Symbol: y + CommonCode: ANN + Description: 'Unit of time equal to 365,25 days.,Synonym: Julian year' + conversion: + factor: 31557600.0 + base_units: + - H04 + - SEC +- Status: X + LevelAndCategory: '3.1' + Name: aluminium pound only + ConversionFactor: '' + Symbol: '' + CommonCode: AP + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: troy ounce or apothecary ounce + ConversionFactor: 3,110 348 x 10⁻³ kg + Symbol: tr oz + CommonCode: APZ + Description: '' + conversion: + factor: 0.003110348 + base_units: [] +- Status: '' + LevelAndCategory: '3.9' + Name: anti-hemophilic factor (AHF) unit + ConversionFactor: '' + Symbol: '' + CommonCode: AQ + Description: A unit of measure for blood potency (US). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: suppository + ConversionFactor: '' + Symbol: '' + CommonCode: AR + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2.0' + Name: are + ConversionFactor: 10² m² + Symbol: a + CommonCode: ARE + Description: 'Synonym: square decametre' + conversion: + factor: 100.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: '3.9' + Name: assortment + ConversionFactor: '' + Symbol: '' + CommonCode: AS + Description: 'A unit of count defining the number of assortments (assortment: set + of items grouped in a mixed collection).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: alcoholic strength by mass + ConversionFactor: '' + Symbol: '' + CommonCode: ASM + Description: A unit of mass defining the alcoholic strength of a liquid. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: alcoholic strength by volume + ConversionFactor: '' + Symbol: '' + CommonCode: ASU + Description: A unit of volume defining the alcoholic strength of a liquid (e.g. + spirit, wine, beer, etc), often at a specific temperature. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: standard atmosphere + ConversionFactor: 1 013 25 Pa + Symbol: atm + CommonCode: ATM + Description: '' + conversion: + factor: 101325.0 + base_units: + - C55 + - PAL +- Status: D + LevelAndCategory: '2' + Name: technical atmosphere + ConversionFactor: 98 066,5 Pa + Symbol: at + CommonCode: ATT + Description: '' + conversion: + factor: 98066.5 + base_units: + - C55 + - PAL +- Status: X + LevelAndCategory: '3.3' + Name: capsule + ConversionFactor: '' + Symbol: '' + CommonCode: AV + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: powder filled vial + ConversionFactor: '' + Symbol: '' + CommonCode: AW + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: american wire gauge + ConversionFactor: '' + Symbol: '' + CommonCode: AWG + Description: A unit of distance used for measuring the diameter of small tubes or + wires such as the outer diameter of hypotermic or suture needles. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: assembly + ConversionFactor: '' + Symbol: '' + CommonCode: AY + Description: 'A unit of count defining the number of assemblies (assembly: items + that consist of component parts).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per pound + ConversionFactor: 2 326 J/kg + Symbol: BtuIT/lb + CommonCode: AZ + Description: '' + conversion: + factor: 2326.0 + base_units: + - J2 +- Status: X + LevelAndCategory: '3.9' + Name: Btu per cubic foot + ConversionFactor: '' + Symbol: BTU/ft³ + CommonCode: B0 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: barrel (US) per day + ConversionFactor: 1,840 13 x 10⁻⁶ m³/s + Symbol: barrel (US)/d + CommonCode: B1 + Description: '' + conversion: + factor: 1.84013e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '3.6' + Name: bit per second + ConversionFactor: '' + Symbol: bit/s + CommonCode: B10 + Description: A unit of information equal to one binary digit per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: joule per kilogram kelvin + ConversionFactor: J/(kg x K) + Symbol: J/(kg·K) + CommonCode: B11 + Description: '' + conversion: + factor: 1.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: '1' + Name: joule per metre + ConversionFactor: J/m + Symbol: J/m + CommonCode: B12 + Description: '' + conversion: + factor: 1.0 + base_units: + - B12 +- Status: '' + LevelAndCategory: '1' + Name: joule per square metre + ConversionFactor: J/m² + Symbol: J/m² + CommonCode: B13 + Description: 'Synonym: joule per metre squared' + conversion: + factor: 1.0 + base_units: + - B13 +- Status: '' + LevelAndCategory: '1' + Name: joule per metre to the fourth power + ConversionFactor: J/m⁴ + Symbol: J/m⁴ + CommonCode: B14 + Description: '' + conversion: + factor: 1.0 + base_units: + - B14 +- Status: '' + LevelAndCategory: '1' + Name: joule per mole + ConversionFactor: J/mol + Symbol: J/mol + CommonCode: B15 + Description: '' + conversion: + factor: 1.0 + base_units: + - B15 +- Status: '' + LevelAndCategory: '1' + Name: joule per mole kelvin + ConversionFactor: J/(mol x K) + Symbol: J/(mol·K) + CommonCode: B16 + Description: '' + conversion: + factor: 1.0 + base_units: + - B16 +- Status: '' + LevelAndCategory: '3.9' + Name: credit + ConversionFactor: '' + Symbol: '' + CommonCode: B17 + Description: A unit of count defining the number of entries made to the credit side + of an account. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: joule second + ConversionFactor: J x s + Symbol: J·s + CommonCode: B18 + Description: '' + conversion: + factor: 1.0 + base_units: + - B18 +- Status: '' + LevelAndCategory: '3.7' + Name: digit + ConversionFactor: '' + Symbol: '' + CommonCode: B19 + Description: A unit of information defining the quantity of numerals used to form + a number. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: bunk + ConversionFactor: '' + Symbol: '' + CommonCode: B2 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: joule square metre per kilogram + ConversionFactor: J x m²/kg + Symbol: J·m²/kg + CommonCode: B20 + Description: '' + conversion: + factor: 1.0 + base_units: + - B20 +- Status: '' + LevelAndCategory: '1' + Name: kelvin per watt + ConversionFactor: K/W + Symbol: K/W + CommonCode: B21 + Description: '' + conversion: + factor: 1.0 + base_units: + - B21 +- Status: '' + LevelAndCategory: 1S + Name: kiloampere + ConversionFactor: 10³ A + Symbol: kA + CommonCode: B22 + Description: '' + conversion: + factor: 1000.0 + base_units: + - AMP +- Status: '' + LevelAndCategory: 1S + Name: kiloampere per square metre + ConversionFactor: 10³ A/m² + Symbol: kA/m² + CommonCode: B23 + Description: '' + conversion: + factor: 1000.0 + base_units: + - A41 +- Status: '' + LevelAndCategory: 1S + Name: kiloampere per metre + ConversionFactor: 10³ A/m + Symbol: kA/m + CommonCode: B24 + Description: '' + conversion: + factor: 1000.0 + base_units: + - AE +- Status: '' + LevelAndCategory: 1S + Name: kilobecquerel per kilogram + ConversionFactor: 10³ Bq/kg + Symbol: kBq/kg + CommonCode: B25 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilocoulomb + ConversionFactor: 10³ C + Symbol: kC + CommonCode: B26 + Description: '' + conversion: + factor: 1000.0 + base_units: + - A8 +- Status: '' + LevelAndCategory: 1S + Name: kilocoulomb per cubic metre + ConversionFactor: 10³ C/m³ + Symbol: kC/m³ + CommonCode: B27 + Description: '' + conversion: + factor: 1000.0 + base_units: + - A29 +- Status: '' + LevelAndCategory: 1S + Name: kilocoulomb per square metre + ConversionFactor: 10³ C/m² + Symbol: kC/m² + CommonCode: B28 + Description: '' + conversion: + factor: 1000.0 + base_units: + - A34 +- Status: '' + LevelAndCategory: 1S + Name: kiloelectronvolt + ConversionFactor: 10³ eV + Symbol: keV + CommonCode: B29 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: batting pound + ConversionFactor: '' + Symbol: '' + CommonCode: B3 + Description: A unit of mass defining the number of pounds of wadded fibre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gibibit + ConversionFactor: '' + Symbol: Gibit + CommonCode: B30 + Description: A unit of information equal to 2³⁰ bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: kilogram metre per second + ConversionFactor: kg x m/s + Symbol: kg·m/s + CommonCode: B31 + Description: '' + conversion: + factor: 1.0 + base_units: + - B31 +- Status: '' + LevelAndCategory: '1' + Name: kilogram metre squared + ConversionFactor: kg x m² + Symbol: kg·m² + CommonCode: B32 + Description: '' + conversion: + factor: 1.0 + base_units: + - B32 +- Status: '' + LevelAndCategory: '1' + Name: kilogram metre squared per second + ConversionFactor: kg x m²/s + Symbol: kg·m²/s + CommonCode: B33 + Description: '' + conversion: + factor: 1.0 + base_units: + - B33 +- Status: '' + LevelAndCategory: 1S + Name: kilogram per cubic decimetre + ConversionFactor: 10³ kg/m³ + Symbol: kg/dm³ + CommonCode: B34 + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1S + Name: kilogram per litre + ConversionFactor: 10³ kg/m³ + Symbol: kg/l or kg/L + CommonCode: B35 + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: D + LevelAndCategory: '2' + Name: calorie (thermochemical) per gram + ConversionFactor: 4 184 J/kg + Symbol: calth/g + CommonCode: B36 + Description: '' + conversion: + factor: 4184.0 + base_units: + - J2 +- Status: D + LevelAndCategory: '2' + Name: kilogram-force + ConversionFactor: 9,806 65 N + Symbol: kgf + CommonCode: B37 + Description: '' + conversion: + factor: 9.80665 + base_units: [] +- Status: D + LevelAndCategory: '2' + Name: kilogram-force metre + ConversionFactor: 9,806 65 N x m + Symbol: kgf·m + CommonCode: B38 + Description: '' + conversion: + factor: 9.80665 + base_units: + - NU +- Status: D + LevelAndCategory: '2' + Name: kilogram-force metre per second + ConversionFactor: 9,806 65 W + Symbol: kgf·m/s + CommonCode: B39 + Description: '' + conversion: + factor: 9.80665 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.5' + Name: barrel, imperial + ConversionFactor: '' + Symbol: '' + CommonCode: B4 + Description: A unit of volume used to measure beer. One beer barrel equals 36 imperial + gallons. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: kilogram-force per square metre + ConversionFactor: 9,806 65 Pa + Symbol: kgf/m² + CommonCode: B40 + Description: '' + conversion: + factor: 9.80665 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: kilojoule per kelvin + ConversionFactor: 10³ J/K + Symbol: kJ/K + CommonCode: B41 + Description: '' + conversion: + factor: 1000.0 + base_units: + - JE +- Status: '' + LevelAndCategory: 1S + Name: kilojoule per kilogram + ConversionFactor: 10³ J/kg + Symbol: kJ/kg + CommonCode: B42 + Description: '' + conversion: + factor: 1000.0 + base_units: + - J2 +- Status: '' + LevelAndCategory: 1S + Name: kilojoule per kilogram kelvin + ConversionFactor: 10³ J/(kg x K) + Symbol: kJ/(kg·K) + CommonCode: B43 + Description: '' + conversion: + factor: 1000.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: 1S + Name: kilojoule per mole + ConversionFactor: 10³ J/mol + Symbol: kJ/mol + CommonCode: B44 + Description: '' + conversion: + factor: 1000.0 + base_units: + - B15 +- Status: '' + LevelAndCategory: 1S + Name: kilomole + ConversionFactor: 10³ mol + Symbol: kmol + CommonCode: B45 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C34 +- Status: '' + LevelAndCategory: 1S + Name: kilomole per cubic metre + ConversionFactor: 10³ mol/m³ + Symbol: kmol/m³ + CommonCode: B46 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C36 + - M33 +- Status: '' + LevelAndCategory: 1S + Name: kilonewton + ConversionFactor: 10³ N + Symbol: kN + CommonCode: B47 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilonewton metre + ConversionFactor: 10³ N x m + Symbol: kN·m + CommonCode: B48 + Description: '' + conversion: + factor: 1000.0 + base_units: + - NU +- Status: '' + LevelAndCategory: 1S + Name: kiloohm + ConversionFactor: 10³ Ω + Symbol: kΩ + CommonCode: B49 + Description: '' + conversion: + factor: 1000.0 + base_units: + - OHM +- Status: X + LevelAndCategory: '3.9' + Name: billet + ConversionFactor: '' + Symbol: '' + CommonCode: B5 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kiloohm metre + ConversionFactor: 10³ Ω x m + Symbol: kΩ·m + CommonCode: B50 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C61 +- Status: D + LevelAndCategory: '2' + Name: kilopond + ConversionFactor: 9,806 65 N + Symbol: kp + CommonCode: B51 + Description: 'Synonym: kilogram-force' + conversion: + factor: 9.80665 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilosecond + ConversionFactor: 10³ s + Symbol: ks + CommonCode: B52 + Description: '' + conversion: + factor: 1000.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: kilosiemens + ConversionFactor: 10³ S + Symbol: kS + CommonCode: B53 + Description: '' + conversion: + factor: 1000.0 + base_units: + - NQ +- Status: '' + LevelAndCategory: 1S + Name: kilosiemens per metre + ConversionFactor: 10³ S/m + Symbol: kS/m + CommonCode: B54 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1S + Name: kilovolt per metre + ConversionFactor: 10³ V/m + Symbol: kV/m + CommonCode: B55 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D50 +- Status: '' + LevelAndCategory: 1S + Name: kiloweber per metre + ConversionFactor: 10³ Wb/m + Symbol: kWb/m + CommonCode: B56 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D59 +- Status: '' + LevelAndCategory: '2' + Name: light year + ConversionFactor: 9,460 73 x 10¹⁵ m + Symbol: ly + CommonCode: B57 + Description: A unit of length defining the distance that light travels in a vacuum + in one year. + conversion: + factor: 9.46073e+15 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: litre per mole + ConversionFactor: 10⁻³ m³/mol + Symbol: l/mol + CommonCode: B58 + Description: '' + conversion: + factor: 0.001 + base_units: + - A40 +- Status: '' + LevelAndCategory: 1S + Name: lumen hour + ConversionFactor: 3,6 x 10³ s x cd x sr + Symbol: lm·h + CommonCode: B59 + Description: '' + conversion: + factor: 3600.0 + base_units: + - B62 +- Status: X + LevelAndCategory: '3.9' + Name: bun + ConversionFactor: '' + Symbol: '' + CommonCode: B6 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: lumen per square metre + ConversionFactor: cd x sr/m² + Symbol: lm/m² + CommonCode: B60 + Description: '' + conversion: + factor: 1.0 + base_units: + - B60 +- Status: '' + LevelAndCategory: '1' + Name: lumen per watt + ConversionFactor: cd x sr/W + Symbol: lm/W + CommonCode: B61 + Description: '' + conversion: + factor: 1.0 + base_units: + - B61 +- Status: '' + LevelAndCategory: '1' + Name: lumen second + ConversionFactor: s x cd x sr + Symbol: lm·s + CommonCode: B62 + Description: '' + conversion: + factor: 1.0 + base_units: + - B62 +- Status: '' + LevelAndCategory: 1S + Name: lux hour + ConversionFactor: 3,6 x 10³ s x cd x sr / m² + Symbol: lx·h + CommonCode: B63 + Description: '' + conversion: + factor: 3600.0 + base_units: + - B64 +- Status: '' + LevelAndCategory: '1' + Name: lux second + ConversionFactor: s x cd x sr / m² + Symbol: lx·s + CommonCode: B64 + Description: '' + conversion: + factor: 1.0 + base_units: + - B64 +- Status: D + LevelAndCategory: '3.5' + Name: maxwell + ConversionFactor: 10⁻⁸ Wb + Symbol: Mx + CommonCode: B65 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - WEB +- Status: '' + LevelAndCategory: 1S + Name: megaampere per square metre + ConversionFactor: 10⁶ A/m² + Symbol: MA/m² + CommonCode: B66 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A41 +- Status: '' + LevelAndCategory: 1S + Name: megabecquerel per kilogram + ConversionFactor: 10⁶ Bq/kg + Symbol: MBq/kg + CommonCode: B67 + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.6' + Name: gigabit + ConversionFactor: '' + Symbol: Gbit + CommonCode: B68 + Description: A unit of information equal to 10⁹ bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megacoulomb per cubic metre + ConversionFactor: 10⁶ C/m³ + Symbol: MC/m³ + CommonCode: B69 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A29 +- Status: '' + LevelAndCategory: '3.9' + Name: cycle + ConversionFactor: '' + Symbol: '' + CommonCode: B7 + Description: 'A unit of count defining the number of cycles (cycle: a recurrent + period of definite duration).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megacoulomb per square metre + ConversionFactor: 10⁶ C/m² + Symbol: MC/m² + CommonCode: B70 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A34 +- Status: '' + LevelAndCategory: 1S + Name: megaelectronvolt + ConversionFactor: 10⁶ eV + Symbol: MeV + CommonCode: B71 + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: megagram per cubic metre + ConversionFactor: 10³ kg/m³ + Symbol: Mg/m³ + CommonCode: B72 + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1S + Name: meganewton + ConversionFactor: 10⁶ N + Symbol: MN + CommonCode: B73 + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: meganewton metre + ConversionFactor: 10⁶ N x m + Symbol: MN·m + CommonCode: B74 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - NU +- Status: '' + LevelAndCategory: 1S + Name: megaohm + ConversionFactor: 10⁶ Ω + Symbol: MΩ + CommonCode: B75 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - OHM +- Status: '' + LevelAndCategory: 1S + Name: megaohm metre + ConversionFactor: 10⁶ Ω x m + Symbol: MΩ·m + CommonCode: B76 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - C61 +- Status: '' + LevelAndCategory: 1S + Name: megasiemens per metre + ConversionFactor: 10⁶ S/m + Symbol: MS/m + CommonCode: B77 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1S + Name: megavolt + ConversionFactor: 10⁶ V + Symbol: MV + CommonCode: B78 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: 1S + Name: megavolt per metre + ConversionFactor: 10⁶ V/m + Symbol: MV/m + CommonCode: B79 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - D50 +- Status: '' + LevelAndCategory: '1' + Name: joule per cubic metre + ConversionFactor: J/m³ + Symbol: J/m³ + CommonCode: B8 + Description: '' + conversion: + factor: 1.0 + base_units: + - B8 +- Status: '' + LevelAndCategory: '3.6' + Name: gigabit per second + ConversionFactor: '' + Symbol: Gbit/s + CommonCode: B80 + Description: A unit of information equal to 10⁹ bits (binary digits) per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal metre squared reciprocal second + ConversionFactor: m⁻²/s + Symbol: m⁻²/s + CommonCode: B81 + Description: '' + conversion: + factor: 1.0 + base_units: + - B81 +- Status: '' + LevelAndCategory: '3.1' + Name: inch per linear foot + ConversionFactor: '' + Symbol: '' + CommonCode: B82 + Description: A unit of length defining the number of inches per linear foot. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: metre to the fourth power + ConversionFactor: m⁴ + Symbol: m⁴ + CommonCode: B83 + Description: '' + conversion: + factor: 1.0 + base_units: + - B83 +- Status: '' + LevelAndCategory: 1S + Name: microampere + ConversionFactor: 10⁻⁶ A + Symbol: µA + CommonCode: B84 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - AMP +- Status: '' + LevelAndCategory: 1S + Name: microbar + ConversionFactor: 10⁻¹ Pa + Symbol: µbar + CommonCode: B85 + Description: '' + conversion: + factor: 0.1 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: microcoulomb + ConversionFactor: 10⁻⁶ C + Symbol: µC + CommonCode: B86 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A8 +- Status: '' + LevelAndCategory: 1S + Name: microcoulomb per cubic metre + ConversionFactor: 10⁻⁶ C/m³ + Symbol: µC/m³ + CommonCode: B87 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A29 +- Status: '' + LevelAndCategory: 1S + Name: microcoulomb per square metre + ConversionFactor: 10⁻⁶ C/m² + Symbol: µC/m² + CommonCode: B88 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A34 +- Status: '' + LevelAndCategory: 1S + Name: microfarad per metre + ConversionFactor: 10⁻⁶ F/m + Symbol: µF/m + CommonCode: B89 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: batt + ConversionFactor: '' + Symbol: '' + CommonCode: B9 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: microhenry + ConversionFactor: 10⁻⁶ H + Symbol: µH + CommonCode: B90 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - '81' +- Status: '' + LevelAndCategory: 1S + Name: microhenry per metre + ConversionFactor: 10⁻⁶ H/m + Symbol: µH/m + CommonCode: B91 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A98 +- Status: '' + LevelAndCategory: 1S + Name: micronewton + ConversionFactor: 10⁻⁶ N + Symbol: µN + CommonCode: B92 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: micronewton metre + ConversionFactor: 10⁻⁶ N x m + Symbol: µN·m + CommonCode: B93 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - NU +- Status: '' + LevelAndCategory: 1S + Name: microohm + ConversionFactor: 10⁻⁶ Ω + Symbol: µΩ + CommonCode: B94 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - OHM +- Status: '' + LevelAndCategory: 1S + Name: microohm metre + ConversionFactor: 10⁻⁶ Ω x m + Symbol: µΩ·m + CommonCode: B95 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C61 +- Status: '' + LevelAndCategory: 1S + Name: micropascal + ConversionFactor: 10⁻⁶ Pa + Symbol: µPa + CommonCode: B96 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: microradian + ConversionFactor: 10⁻⁶ rad + Symbol: µrad + CommonCode: B97 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C81 +- Status: '' + LevelAndCategory: 1S + Name: microsecond + ConversionFactor: 10⁻⁶ s + Symbol: µs + CommonCode: B98 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: microsiemens + ConversionFactor: 10⁻⁶ S + Symbol: µS + CommonCode: B99 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - NQ +- Status: '' + LevelAndCategory: '1' + Name: bar [unit of pressure] + ConversionFactor: 10⁵ Pa + Symbol: bar + CommonCode: BAR + Description: '' + conversion: + factor: 100000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.5' + Name: base box + ConversionFactor: '' + Symbol: '' + CommonCode: BB + Description: A unit of area of 112 sheets of tin mil products (tin plate, tin free + steel or black plate) 14 by 20 inches, or 31,360 square inches. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: board + ConversionFactor: '' + Symbol: '' + CommonCode: BD + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bundle + ConversionFactor: '' + Symbol: '' + CommonCode: BE + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: board foot + ConversionFactor: '' + Symbol: fbm + CommonCode: BFT + Description: 'A unit of volume defining the number of cords (cord: a stack of firewood + of 128 cubic feet).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bag + ConversionFactor: '' + Symbol: '' + CommonCode: BG + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: brush + ConversionFactor: '' + Symbol: '' + CommonCode: BH + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: brake horse power + ConversionFactor: 7,457 x 10² W + Symbol: '' + CommonCode: BHP + Description: '' + conversion: + factor: 745.7 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.7' + Name: billion (EUR) + ConversionFactor: 10¹² + Symbol: '' + CommonCode: BIL + Description: 'Synonym: trillion (US)' + conversion: + factor: 1000000000000.0 +- Status: X + LevelAndCategory: '3.3' + Name: bucket + ConversionFactor: '' + Symbol: '' + CommonCode: BJ + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: basket + ConversionFactor: '' + Symbol: '' + CommonCode: BK + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bale + ConversionFactor: '' + Symbol: '' + CommonCode: BL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: dry barrel (US) + ConversionFactor: 1,156 27 x 10⁻¹ m³ + Symbol: bbl (US) + CommonCode: BLD + Description: '' + conversion: + factor: 0.115627 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: barrel (US) + ConversionFactor: 158,987 3 x 10⁻³ m³ + Symbol: barrel (US) + CommonCode: BLL + Description: '' + conversion: + factor: 0.1589873 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.3' + Name: bottle + ConversionFactor: '' + Symbol: '' + CommonCode: BO + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: hundred board foot + ConversionFactor: '' + Symbol: '' + CommonCode: BP + Description: A unit of volume equal to one hundred board foot. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: beats per minute + ConversionFactor: 1.667 x 10-2 /s + Symbol: '' + CommonCode: BPM + Description: The number of beats per minute. + conversion: + factor: 1.0 + base_units: + - BPM + - OPM +- Status: '' + LevelAndCategory: '1' + Name: becquerel + ConversionFactor: 27,027 x 10⁻¹² Ci + Symbol: Bq + CommonCode: BQL + Description: '' + conversion: + factor: 2.7027e-11 + base_units: [] +- Status: X + LevelAndCategory: '3.3' + Name: bar [unit of packaging] + ConversionFactor: '' + Symbol: '' + CommonCode: BR + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bolt + ConversionFactor: '' + Symbol: '' + CommonCode: BT + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) + ConversionFactor: 1,055 056 x 10³ J + Symbol: BtuIT + CommonCode: BTU + Description: '' + conversion: + factor: 1055.056 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: bushel (US) + ConversionFactor: 3,523 907 x 10⁻² m³ + Symbol: bu (US) + CommonCode: BUA + Description: '' + conversion: + factor: 0.03523907 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: bushel (UK) + ConversionFactor: 3,636 872 x 10⁻² m³ + Symbol: bushel (UK) + CommonCode: BUI + Description: '' + conversion: + factor: 0.03636872 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.9' + Name: base weight + ConversionFactor: '' + Symbol: '' + CommonCode: BW + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: box + ConversionFactor: '' + Symbol: '' + CommonCode: BX + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: million BTUs + ConversionFactor: '' + Symbol: '' + CommonCode: BZ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: call + ConversionFactor: '' + Symbol: '' + CommonCode: C0 + Description: 'A unit of count defining the number of calls (call: communication + session or visitation).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: composite product pound (total weight) + ConversionFactor: '' + Symbol: '' + CommonCode: C1 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millifarad + ConversionFactor: 10⁻³ F + Symbol: mF + CommonCode: C10 + Description: '' + conversion: + factor: 0.001 + base_units: + - FAR +- Status: '' + LevelAndCategory: 1M + Name: milligal + ConversionFactor: 10⁻⁵ m/s² + Symbol: mGal + CommonCode: C11 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: 1S + Name: milligram per metre + ConversionFactor: 10⁻⁶ kg/m + Symbol: mg/m + CommonCode: C12 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - KL +- Status: '' + LevelAndCategory: 1S + Name: milligray + ConversionFactor: 10⁻³ Gy + Symbol: mGy + CommonCode: C13 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: millihenry + ConversionFactor: 10⁻³ H + Symbol: mH + CommonCode: C14 + Description: '' + conversion: + factor: 0.001 + base_units: + - '81' +- Status: '' + LevelAndCategory: 1S + Name: millijoule + ConversionFactor: 10⁻³ J + Symbol: mJ + CommonCode: C15 + Description: '' + conversion: + factor: 0.001 + base_units: + - JOU +- Status: '' + LevelAndCategory: 1S + Name: millimetre per second + ConversionFactor: 10⁻³ m/s + Symbol: mm/s + CommonCode: C16 + Description: '' + conversion: + factor: 0.001 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: 1S + Name: millimetre squared per second + ConversionFactor: 10⁻⁶ m²/s + Symbol: mm²/s + CommonCode: C17 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - S4 +- Status: '' + LevelAndCategory: 1S + Name: millimole + ConversionFactor: 10⁻³ mol + Symbol: mmol + CommonCode: C18 + Description: '' + conversion: + factor: 0.001 + base_units: + - C34 +- Status: '' + LevelAndCategory: '1' + Name: mole per kilogram + ConversionFactor: mol/kg + Symbol: mol/kg + CommonCode: C19 + Description: '' + conversion: + factor: 1.0 + base_units: + - C19 +- Status: X + LevelAndCategory: '3.5' + Name: carset + ConversionFactor: '' + Symbol: '' + CommonCode: C2 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millinewton + ConversionFactor: 10⁻³ N + Symbol: mN + CommonCode: C20 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '3.6' + Name: kibibit + ConversionFactor: '' + Symbol: Kibit + CommonCode: C21 + Description: A unit of information equal to 2¹⁰ (1024) bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millinewton per metre + ConversionFactor: 10⁻³ N/m + Symbol: mN/m + CommonCode: C22 + Description: '' + conversion: + factor: 0.001 + base_units: + - 4P +- Status: '' + LevelAndCategory: 1S + Name: milliohm metre + ConversionFactor: 10⁻³ Ω x m + Symbol: mΩ·m + CommonCode: C23 + Description: '' + conversion: + factor: 0.001 + base_units: + - C61 +- Status: '' + LevelAndCategory: 1S + Name: millipascal second + ConversionFactor: 10⁻³ Pa x s + Symbol: mPa·s + CommonCode: C24 + Description: '' + conversion: + factor: 0.001 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: 1S + Name: milliradian + ConversionFactor: 10⁻³ rad + Symbol: mrad + CommonCode: C25 + Description: '' + conversion: + factor: 0.001 + base_units: + - C81 +- Status: '' + LevelAndCategory: 1S + Name: millisecond + ConversionFactor: 10⁻³ s + Symbol: ms + CommonCode: C26 + Description: '' + conversion: + factor: 0.001 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: millisiemens + ConversionFactor: 10⁻³ S + Symbol: mS + CommonCode: C27 + Description: '' + conversion: + factor: 0.001 + base_units: + - NQ +- Status: '' + LevelAndCategory: 1S + Name: millisievert + ConversionFactor: 10⁻³ Sv + Symbol: mSv + CommonCode: C28 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: millitesla + ConversionFactor: 10⁻³ T + Symbol: mT + CommonCode: C29 + Description: '' + conversion: + factor: 0.001 + base_units: + - D33 +- Status: '' + LevelAndCategory: 1S + Name: microvolt per metre + ConversionFactor: 10⁻⁶ V/m + Symbol: µV/m + CommonCode: C3 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D50 +- Status: '' + LevelAndCategory: 1S + Name: millivolt per metre + ConversionFactor: 10⁻³ V/m + Symbol: mV/m + CommonCode: C30 + Description: '' + conversion: + factor: 0.001 + base_units: + - D50 +- Status: '' + LevelAndCategory: 1S + Name: milliwatt + ConversionFactor: 10⁻³ W + Symbol: mW + CommonCode: C31 + Description: '' + conversion: + factor: 0.001 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1S + Name: milliwatt per square metre + ConversionFactor: 10⁻³ W/m² + Symbol: mW/m² + CommonCode: C32 + Description: '' + conversion: + factor: 0.001 + base_units: + - D54 +- Status: '' + LevelAndCategory: 1S + Name: milliweber + ConversionFactor: 10⁻³ Wb + Symbol: mWb + CommonCode: C33 + Description: '' + conversion: + factor: 0.001 + base_units: + - WEB +- Status: '' + LevelAndCategory: '1' + Name: mole + ConversionFactor: mol + Symbol: mol + CommonCode: C34 + Description: '' + conversion: + factor: 1.0 + base_units: + - C34 +- Status: '' + LevelAndCategory: 1S + Name: mole per cubic decimetre + ConversionFactor: 10³ mol/m³ + Symbol: mol/dm³ + CommonCode: C35 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C36 + - M33 +- Status: '' + LevelAndCategory: '1' + Name: mole per cubic metre + ConversionFactor: mol/m³ + Symbol: mol/m³ + CommonCode: C36 + Description: '' + conversion: + factor: 1.0 + base_units: + - C36 + - M33 +- Status: '' + LevelAndCategory: '3.6' + Name: kilobit + ConversionFactor: '' + Symbol: kbit + CommonCode: C37 + Description: A unit of information equal to 10³ (1000) bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: mole per litre + ConversionFactor: 10³ mol/m³ + Symbol: mol/l + CommonCode: C38 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C36 + - M33 +- Status: '' + LevelAndCategory: 1S + Name: nanoampere + ConversionFactor: 10⁻⁹ A + Symbol: nA + CommonCode: C39 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: X + LevelAndCategory: '3.5' + Name: carload + ConversionFactor: '' + Symbol: '' + CommonCode: C4 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: nanocoulomb + ConversionFactor: 10⁻⁹ C + Symbol: nC + CommonCode: C40 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanofarad + ConversionFactor: 10⁻⁹ F + Symbol: nF + CommonCode: C41 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanofarad per metre + ConversionFactor: 10⁻⁹ F/m + Symbol: nF/m + CommonCode: C42 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanohenry + ConversionFactor: 10⁻⁹ H + Symbol: nH + CommonCode: C43 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanohenry per metre + ConversionFactor: 10⁻⁹ H/m + Symbol: nH/m + CommonCode: C44 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanometre + ConversionFactor: 10⁻⁹ m + Symbol: nm + CommonCode: C45 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanoohm metre + ConversionFactor: 10⁻⁹ Ω·x m + Symbol: nΩ·m + CommonCode: C46 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanosecond + ConversionFactor: 10⁻⁹ s + Symbol: ns + CommonCode: C47 + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: nanotesla + ConversionFactor: 10⁻⁹ T + Symbol: nT + CommonCode: C48 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanowatt + ConversionFactor: 10⁻⁹ W + Symbol: nW + CommonCode: C49 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: cost + ConversionFactor: '' + Symbol: '' + CommonCode: C5 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: neper + ConversionFactor: Np + Symbol: Np + CommonCode: C50 + Description: '' + conversion: + factor: 1.0 + base_units: + - C50 +- Status: '' + LevelAndCategory: '1' + Name: neper per second + ConversionFactor: Np/s + Symbol: Np/s + CommonCode: C51 + Description: '' + conversion: + factor: 1.0 + base_units: + - C51 +- Status: '' + LevelAndCategory: 1S + Name: picometre + ConversionFactor: 10⁻¹² m + Symbol: pm + CommonCode: C52 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - MTR +- Status: '' + LevelAndCategory: '1' + Name: newton metre second + ConversionFactor: N x m x s + Symbol: N·m·s + CommonCode: C53 + Description: '' + conversion: + factor: 1.0 + base_units: + - C53 +- Status: '' + LevelAndCategory: '1' + Name: newton metre squared per kilogram squared + ConversionFactor: N x m²/kg² + Symbol: N·m²/kg² + CommonCode: C54 + Description: '' + conversion: + factor: 1.0 + base_units: + - C54 +- Status: '' + LevelAndCategory: 1S + Name: newton per square metre + ConversionFactor: Pa + Symbol: N/m² + CommonCode: C55 + Description: '' + conversion: + factor: 1.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: newton per square millimetre + ConversionFactor: 10⁶ Pa + Symbol: N/mm² + CommonCode: C56 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '1' + Name: newton second + ConversionFactor: N x s + Symbol: N·s + CommonCode: C57 + Description: '' + conversion: + factor: 1.0 + base_units: + - C57 +- Status: '' + LevelAndCategory: '1' + Name: newton second per metre + ConversionFactor: N x s/m + Symbol: N·s/m + CommonCode: C58 + Description: '' + conversion: + factor: 1.0 + base_units: + - C58 +- Status: '' + LevelAndCategory: '1' + Name: octave + ConversionFactor: '' + Symbol: '' + CommonCode: C59 + Description: A unit used in music to describe the ratio in frequency between notes. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: cell + ConversionFactor: '' + Symbol: '' + CommonCode: C6 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: ohm centimetre + ConversionFactor: '10⁻² Ω x m ' + Symbol: Ω·cm + CommonCode: C60 + Description: '' + conversion: + factor: 0.01 + base_units: + - C61 +- Status: '' + LevelAndCategory: '1' + Name: ohm metre + ConversionFactor: Ω x m + Symbol: Ω·m + CommonCode: C61 + Description: '' + conversion: + factor: 1.0 + base_units: + - C61 +- Status: '' + LevelAndCategory: '1' + Name: one + ConversionFactor: '1' + Symbol: '1' + CommonCode: C62 + Description: 'Synonym: unit' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: parsec + ConversionFactor: 3,085 678 x 10¹⁶ m + Symbol: pc + CommonCode: C63 + Description: '' + conversion: + factor: 3.085678e+16 + base_units: + - MTR +- Status: '' + LevelAndCategory: '1' + Name: pascal per kelvin + ConversionFactor: Pa/K + Symbol: Pa/K + CommonCode: C64 + Description: '' + conversion: + factor: 1.0 + base_units: + - C64 +- Status: '' + LevelAndCategory: '1' + Name: pascal second + ConversionFactor: Pa x s + Symbol: Pa·s + CommonCode: C65 + Description: '' + conversion: + factor: 1.0 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '1' + Name: pascal second per cubic metre + ConversionFactor: Pa x s/m³ + Symbol: Pa·s/m³ + CommonCode: C66 + Description: '' + conversion: + factor: 1.0 + base_units: + - C66 +- Status: '' + LevelAndCategory: '1' + Name: pascal second per metre + ConversionFactor: Pa x s/m + Symbol: Pa· s/m + CommonCode: C67 + Description: '' + conversion: + factor: 1.0 + base_units: + - C67 +- Status: '' + LevelAndCategory: 1S + Name: petajoule + ConversionFactor: 10¹⁵ J + Symbol: PJ + CommonCode: C68 + Description: '' + conversion: + factor: 1.0e+15 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: phon + ConversionFactor: '' + Symbol: '' + CommonCode: C69 + Description: A unit of subjective sound loudness. A sound has loudness p phons if + it seems to the listener to be equal in loudness to the sound of a pure tone of + frequency 1 kilohertz and strength p decibels. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: centipoise + ConversionFactor: 10⁻³ Pa x s + Symbol: cP + CommonCode: C7 + Description: '' + conversion: + factor: 0.001 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: 1S + Name: picoampere + ConversionFactor: 10⁻¹² A + Symbol: pA + CommonCode: C70 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - AMP +- Status: '' + LevelAndCategory: 1S + Name: picocoulomb + ConversionFactor: 10⁻¹² C + Symbol: pC + CommonCode: C71 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - A8 +- Status: '' + LevelAndCategory: 1S + Name: picofarad per metre + ConversionFactor: 10⁻¹² F/m + Symbol: pF/m + CommonCode: C72 + Description: '' + conversion: + factor: 1.0e-12 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: picohenry + ConversionFactor: 10⁻¹² H + Symbol: pH + CommonCode: C73 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - '81' +- Status: '' + LevelAndCategory: '3.6' + Name: kilobit per second + ConversionFactor: 10³ bit/s + Symbol: kbit/s + CommonCode: C74 + Description: A unit of information equal to 10³ (1000) bits (binary digits) per + second. + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: picowatt + ConversionFactor: 10⁻¹² W + Symbol: pW + CommonCode: C75 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1S + Name: picowatt per square metre + ConversionFactor: 10⁻¹² W/m² + Symbol: pW/m² + CommonCode: C76 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - D54 +- Status: X + LevelAndCategory: '3.1' + Name: pound gage + ConversionFactor: '' + Symbol: '' + CommonCode: C77 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: pound-force + ConversionFactor: 4,448 222 N + Symbol: lbf + CommonCode: C78 + Description: '' + conversion: + factor: 4.448222 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: kilovolt ampere hour + ConversionFactor: '' + Symbol: kVAh + CommonCode: C79 + Description: A unit of accumulated energy of 1000 volt amperes over a period of + one hour. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millicoulomb per kilogram + ConversionFactor: 10⁻³ C/kg + Symbol: mC/kg + CommonCode: C8 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: rad + ConversionFactor: 10⁻² Gy + Symbol: rad + CommonCode: C80 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: radian + ConversionFactor: rad + Symbol: rad + CommonCode: C81 + Description: '' + conversion: + factor: 1.0 + base_units: + - C81 +- Status: '' + LevelAndCategory: '1' + Name: radian square metre per mole + ConversionFactor: rad x m²/mol + Symbol: rad·m²/mol + CommonCode: C82 + Description: '' + conversion: + factor: 1.0 + base_units: + - C82 +- Status: '' + LevelAndCategory: '1' + Name: radian square metre per kilogram + ConversionFactor: rad x m²/kg + Symbol: rad·m²/kg + CommonCode: C83 + Description: '' + conversion: + factor: 1.0 + base_units: + - C83 +- Status: '' + LevelAndCategory: '1' + Name: radian per metre + ConversionFactor: rad/m + Symbol: rad/m + CommonCode: C84 + Description: '' + conversion: + factor: 1.0 + base_units: + - C84 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal angstrom + ConversionFactor: 10¹⁰ m⁻¹ + Symbol: Å⁻¹ + CommonCode: C85 + Description: '' + conversion: + factor: 10000000000.0 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal cubic metre + ConversionFactor: m⁻³ + Symbol: m⁻³ + CommonCode: C86 + Description: '' + conversion: + factor: 1.0 + base_units: + - C86 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal cubic metre per second + ConversionFactor: m⁻³/s + Symbol: m⁻³/s + CommonCode: C87 + Description: 'Synonym: reciprocal second per cubic metre' + conversion: + factor: 1.0 + base_units: + - C87 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal electron volt per cubic metre + ConversionFactor: 6,241 46 x 10¹⁸ J⁻¹/m³ + Symbol: eV⁻¹/m³ + CommonCode: C88 + Description: '' + conversion: + factor: 6.24146e+18 + base_units: + - C90 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal henry + ConversionFactor: H⁻¹ + Symbol: H⁻¹ + CommonCode: C89 + Description: '' + conversion: + factor: 1.0 + base_units: + - C89 +- Status: '' + LevelAndCategory: '3.9' + Name: coil group + ConversionFactor: '' + Symbol: '' + CommonCode: C9 + Description: 'A unit of count defining the number of coil groups (coil group: groups + of items arranged by lengths of those items placed in a joined sequence of concentric + circles).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal joule per cubic metre + ConversionFactor: J⁻¹/m³ + Symbol: J⁻¹/m³ + CommonCode: C90 + Description: '' + conversion: + factor: 1.0 + base_units: + - C90 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal kelvin or kelvin to the power minus one + ConversionFactor: K⁻¹ + Symbol: K⁻¹ + CommonCode: C91 + Description: '' + conversion: + factor: 1.0 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal metre + ConversionFactor: m⁻¹ + Symbol: m⁻¹ + CommonCode: C92 + Description: '' + conversion: + factor: 1.0 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal square metre + ConversionFactor: m⁻² + Symbol: m⁻² + CommonCode: C93 + Description: 'Synonym: reciprocal metre squared' + conversion: + factor: 1.0 + base_units: + - C93 +- Status: '' + LevelAndCategory: 1S + Name: reciprocal minute + ConversionFactor: 1,666 667 x 10⁻² s + Symbol: min⁻¹ + CommonCode: C94 + Description: '' + conversion: + factor: 0.01666667 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '1' + Name: reciprocal mole + ConversionFactor: mol⁻¹ + Symbol: mol⁻¹ + CommonCode: C95 + Description: '' + conversion: + factor: 1.0 + base_units: + - C95 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal pascal or pascal to the power minus one + ConversionFactor: Pa⁻¹ + Symbol: Pa⁻¹ + CommonCode: C96 + Description: '' + conversion: + factor: 1.0 + base_units: + - C96 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal second + ConversionFactor: s⁻¹ + Symbol: s⁻¹ + CommonCode: C97 + Description: '' + conversion: + factor: 1.0 + base_units: + - C97 +- Status: X + LevelAndCategory: '1' + Name: reciprocal second per cubic metre + ConversionFactor: s⁻¹/m³ + Symbol: s⁻¹/m³ + CommonCode: C98 + Description: '' + conversion: + factor: 1.0 + base_units: + - C98 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal second per metre squared + ConversionFactor: s⁻¹/m² + Symbol: s⁻¹/m² + CommonCode: C99 + Description: '' + conversion: + factor: 1.0 + base_units: + - C99 +- Status: X + LevelAndCategory: '3.3' + Name: can + ConversionFactor: '' + Symbol: '' + CommonCode: CA + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: carrying capacity in metric ton + ConversionFactor: '' + Symbol: '' + CommonCode: CCT + Description: A unit of mass defining the carrying capacity, expressed as the number + of metric tons. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: candela + ConversionFactor: cd + Symbol: cd + CommonCode: CDL + Description: '' + conversion: + factor: 1.0 + base_units: + - CDL +- Status: '' + LevelAndCategory: '1' + Name: degree Celsius + ConversionFactor: 1 x K + Symbol: "°C" + CommonCode: CEL + Description: 'Refer ISO 80000-5 (Quantities and units — Part 5: Thermodynamics)' + conversion: + factor: 1.0 + base_units: + - CEL + - KEL +- Status: '' + LevelAndCategory: '3.7' + Name: hundred + ConversionFactor: '100' + Symbol: '' + CommonCode: CEN + Description: A unit of count defining the number of units in multiples of 100. + conversion: + factor: 100.0 +- Status: '' + LevelAndCategory: '3.9' + Name: card + ConversionFactor: '' + Symbol: '' + CommonCode: CG + Description: 'A unit of count defining the number of units of card (card: thick + stiff paper or cardboard).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: centigram + ConversionFactor: 10⁻⁵ kg + Symbol: cg + CommonCode: CGM + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.4' + Name: container + ConversionFactor: '' + Symbol: '' + CommonCode: CH + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: cone + ConversionFactor: '' + Symbol: '' + CommonCode: CJ + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: connector + ConversionFactor: '' + Symbol: '' + CommonCode: CK + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: coulomb per kilogram + ConversionFactor: A x s/kg + Symbol: C/kg + CommonCode: CKG + Description: '' + conversion: + factor: 1.0 + base_units: + - CKG +- Status: X + LevelAndCategory: '3.3' + Name: coil + ConversionFactor: '' + Symbol: '' + CommonCode: CL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: hundred leave + ConversionFactor: '' + Symbol: '' + CommonCode: CLF + Description: A unit of count defining the number of leaves, expressed in units of + one hundred leaves. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: centilitre + ConversionFactor: 10⁻⁵ m³ + Symbol: cl + CommonCode: CLT + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: square centimetre + ConversionFactor: 10⁻⁴ m² + Symbol: cm² + CommonCode: CMK + Description: '' + conversion: + factor: 0.0001 + base_units: + - MTK +- Status: '' + LevelAndCategory: 1S + Name: cubic centimetre + ConversionFactor: 10⁻⁶ m³ + Symbol: cm³ + CommonCode: CMQ + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S,3.5 + Name: centimetre + ConversionFactor: 10⁻² m + Symbol: cm + CommonCode: CMT + Description: '' + conversion: + factor: 0.01 + base_units: + - MTR +- Status: '' + LevelAndCategory: 3.2,3.8 + Name: hundred pack + ConversionFactor: '' + Symbol: '' + CommonCode: CNP + Description: 'A unit of count defining the number of hundred-packs (hundred-pack: + set of one hundred items packaged together).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: cental (UK) + ConversionFactor: 45,359 237 kg + Symbol: '' + CommonCode: CNT + Description: A unit of mass equal to one hundred weight (US). + conversion: + factor: 45.359237 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.3' + Name: carboy + ConversionFactor: '' + Symbol: '' + CommonCode: CO + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: coulomb + ConversionFactor: A x s + Symbol: C + CommonCode: COU + Description: '' + conversion: + factor: 1.0 + base_units: + - COU +- Status: X + LevelAndCategory: '3.9' + Name: cartridge + ConversionFactor: '' + Symbol: '' + CommonCode: CQ + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: crate + ConversionFactor: '' + Symbol: '' + CommonCode: CR + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: case + ConversionFactor: '' + Symbol: '' + CommonCode: CS + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: carton + ConversionFactor: '' + Symbol: '' + CommonCode: CT + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: content gram + ConversionFactor: '' + Symbol: '' + CommonCode: CTG + Description: A unit of mass defining the number of grams of a named item in a product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: metric carat + ConversionFactor: 200 mg + Symbol: '' + CommonCode: CTM + Description: '' + conversion: + factor: 200.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: content ton (metric) + ConversionFactor: '' + Symbol: '' + CommonCode: CTN + Description: A unit of mass defining the number of metric tons of a named item in + a product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: cup + ConversionFactor: '' + Symbol: '' + CommonCode: CU + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: curie + ConversionFactor: 3,7 x 10¹⁰ Bq + Symbol: Ci + CommonCode: CUR + Description: '' + conversion: + factor: 37000000000.0 + base_units: [] +- Status: X + LevelAndCategory: '3.3' + Name: cover + ConversionFactor: '' + Symbol: '' + CommonCode: CV + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: hundred pound (cwt) / hundred weight (US) + ConversionFactor: 45,359 2 kg + Symbol: cwt (US) + CommonCode: CWA + Description: '' + conversion: + factor: 45.3592 + base_units: + - KGM +- Status: '' + LevelAndCategory: '2' + Name: hundred weight (UK) + ConversionFactor: 50,802 35 kg + Symbol: cwt (UK) + CommonCode: CWI + Description: '' + conversion: + factor: 50.80235 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.3' + Name: cylinder + ConversionFactor: '' + Symbol: '' + CommonCode: CY + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: combo + ConversionFactor: '' + Symbol: '' + CommonCode: CZ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilowatt hour per hour + ConversionFactor: '' + Symbol: kW·h/h + CommonCode: D03 + Description: A unit of accumulated energy of a thousand watts over a period of one + hour. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.2' + Name: lot [unit of weight] + ConversionFactor: '' + Symbol: '' + CommonCode: D04 + Description: A unit of weight equal to about 1/2 ounce or 15 grams. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal second per steradian + ConversionFactor: s⁻¹/sr + Symbol: s⁻¹/sr + CommonCode: D1 + Description: '' + conversion: + factor: 1.0 + base_units: + - D1 +- Status: '' + LevelAndCategory: '1' + Name: siemens per metre + ConversionFactor: S/m + Symbol: S/m + CommonCode: D10 + Description: '' + conversion: + factor: 1.0 + base_units: + - D10 +- Status: '' + LevelAndCategory: '3.6' + Name: mebibit + ConversionFactor: '' + Symbol: Mibit + CommonCode: D11 + Description: A unit of information equal to 2²⁰ (1048576) bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: siemens square metre per mole + ConversionFactor: S x m²/mol + Symbol: S·m²/mol + CommonCode: D12 + Description: '' + conversion: + factor: 1.0 + base_units: + - D12 +- Status: '' + LevelAndCategory: '1' + Name: sievert + ConversionFactor: m²/s² + Symbol: Sv + CommonCode: D13 + Description: '' + conversion: + factor: 1.0 + base_units: + - A95 + - D13 +- Status: X + LevelAndCategory: '3.8' + Name: thousand linear yard + ConversionFactor: '' + Symbol: '' + CommonCode: D14 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: sone + ConversionFactor: '' + Symbol: '' + CommonCode: D15 + Description: A unit of subjective sound loudness. One sone is the loudness of a + pure tone of frequency one kilohertz and strength 40 decibels. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: square centimetre per erg + ConversionFactor: 10³ m²/J + Symbol: cm²/erg + CommonCode: D16 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D20 +- Status: '' + LevelAndCategory: '2' + Name: square centimetre per steradian erg + ConversionFactor: 10³ m²/(sr x J) + Symbol: cm²/(sr·erg) + CommonCode: D17 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D25 +- Status: '' + LevelAndCategory: '1' + Name: metre kelvin + ConversionFactor: m x K + Symbol: m·K + CommonCode: D18 + Description: '' + conversion: + factor: 1.0 + base_units: + - D18 +- Status: '' + LevelAndCategory: '1' + Name: square metre kelvin per watt + ConversionFactor: m² x K/W + Symbol: m²·K/W + CommonCode: D19 + Description: '' + conversion: + factor: 1.0 + base_units: + - D19 +- Status: '' + LevelAndCategory: '1' + Name: reciprocal second per steradian metre squared + ConversionFactor: s⁻¹/(sr x m²) + Symbol: s⁻¹/(sr·m²) + CommonCode: D2 + Description: '' + conversion: + factor: 1.0 + base_units: + - D2 +- Status: '' + LevelAndCategory: '1' + Name: square metre per joule + ConversionFactor: m²/J + Symbol: m²/J + CommonCode: D20 + Description: '' + conversion: + factor: 1.0 + base_units: + - D20 +- Status: '' + LevelAndCategory: '1' + Name: square metre per kilogram + ConversionFactor: m²/kg + Symbol: m²/kg + CommonCode: D21 + Description: '' + conversion: + factor: 1.0 + base_units: + - D21 +- Status: '' + LevelAndCategory: '1' + Name: square metre per mole + ConversionFactor: m²/mol + Symbol: m²/mol + CommonCode: D22 + Description: '' + conversion: + factor: 1.0 + base_units: + - D22 +- Status: '' + LevelAndCategory: '3.9' + Name: pen gram (protein) + ConversionFactor: '' + Symbol: '' + CommonCode: D23 + Description: A unit of count defining the number of grams of amino acid prescribed + for parenteral/enteral therapy. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: square metre per steradian + ConversionFactor: m²/sr + Symbol: m²/sr + CommonCode: D24 + Description: '' + conversion: + factor: 1.0 + base_units: + - D24 +- Status: '' + LevelAndCategory: '1' + Name: square metre per steradian joule + ConversionFactor: m²/(sr x J) + Symbol: m²/(sr·J) + CommonCode: D25 + Description: '' + conversion: + factor: 1.0 + base_units: + - D25 +- Status: '' + LevelAndCategory: '1' + Name: square metre per volt second + ConversionFactor: m²/(V x s) + Symbol: m²/(V·s) + CommonCode: D26 + Description: '' + conversion: + factor: 1.0 + base_units: + - D26 +- Status: '' + LevelAndCategory: '1' + Name: steradian + ConversionFactor: sr + Symbol: sr + CommonCode: D27 + Description: '' + conversion: + factor: 1.0 + base_units: + - D27 +- Status: X + LevelAndCategory: '3.9' + Name: syphon + ConversionFactor: '' + Symbol: '' + CommonCode: D28 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: terahertz + ConversionFactor: 10¹² Hz + Symbol: THz + CommonCode: D29 + Description: '' + conversion: + factor: 1000000000000.0 + base_units: + - HTZ +- Status: '' + LevelAndCategory: 1S + Name: terajoule + ConversionFactor: 10¹² J + Symbol: TJ + CommonCode: D30 + Description: '' + conversion: + factor: 1000000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: terawatt + ConversionFactor: 10¹² W + Symbol: TW + CommonCode: D31 + Description: '' + conversion: + factor: 1000000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: terawatt hour + ConversionFactor: 3,6 x 10¹⁵ J + Symbol: TW·h + CommonCode: D32 + Description: '' + conversion: + factor: 3.6e+15 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: tesla + ConversionFactor: T + Symbol: T + CommonCode: D33 + Description: '' + conversion: + factor: 1.0 + base_units: + - D33 +- Status: '' + LevelAndCategory: '3.5' + Name: tex + ConversionFactor: 10⁻⁶ kg/m + Symbol: tex (g/km) + CommonCode: D34 + Description: A unit of yarn density. One decitex equals a mass of 1 gram per 1 kilometre + of length. + conversion: + factor: 1.0e-06 + base_units: + - KL +- Status: D + LevelAndCategory: '2' + Name: calorie (thermochemical) + ConversionFactor: 4,184 J + Symbol: calth + CommonCode: D35 + Description: '' + conversion: + factor: 4.184 + base_units: + - JOU +- Status: '' + LevelAndCategory: '3.6' + Name: megabit + ConversionFactor: '' + Symbol: Mbit + CommonCode: D36 + Description: A unit of information equal to 10⁶ (1000000) bits (binary digits). + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: calorie (thermochemical) per gram kelvin + ConversionFactor: 4,184 x 10³ J/(kg x K) + Symbol: calth/(g·K) + CommonCode: D37 + Description: '' + conversion: + factor: 4184.0 + base_units: + - B11 +- Status: D + LevelAndCategory: '2' + Name: calorie (thermochemical) per second centimetre kelvin + ConversionFactor: 418,4 W/(m x K) + Symbol: calth/(s·cm·K) + CommonCode: D38 + Description: '' + conversion: + factor: 418.4 + base_units: + - D53 + - N80 +- Status: D + LevelAndCategory: '2' + Name: calorie (thermochemical) per second square centimetre kelvin + ConversionFactor: 4,184 x10⁴ W/(m² x K) + Symbol: calth/(s·cm²·K) + CommonCode: D39 + Description: '' + conversion: + factor: 4.184 + base_units: [] +- Status: X + LevelAndCategory: '3.8' + Name: thousand litre + ConversionFactor: m³ + Symbol: '' + CommonCode: D40 + Description: '' + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: tonne per cubic metre + ConversionFactor: 10³ kg/m³ + Symbol: t/m³ + CommonCode: D41 + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: tropical year + ConversionFactor: 3,155 692 5 x 10⁷ s + Symbol: y (tropical) + CommonCode: D42 + Description: '' + conversion: + factor: 3.155692 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: unified atomic mass unit + ConversionFactor: 1,660 538 782 x 10⁻²⁷ kg + Symbol: u + CommonCode: D43 + Description: '' + conversion: + factor: 1.66 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: var + ConversionFactor: V x A + Symbol: var + CommonCode: D44 + Description: The name of the unit is an acronym for volt-ampere-reactive. + conversion: + factor: 1.0 + base_units: + - D44 +- Status: '' + LevelAndCategory: '1' + Name: volt squared per kelvin squared + ConversionFactor: V²/K² + Symbol: V²/K² + CommonCode: D45 + Description: '' + conversion: + factor: 1.0 + base_units: + - D45 +- Status: '' + LevelAndCategory: '1' + Name: volt - ampere + ConversionFactor: W + Symbol: V·A + CommonCode: D46 + Description: '' + conversion: + factor: 1.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1S + Name: volt per centimetre + ConversionFactor: V/m x 10² + Symbol: V/cm + CommonCode: D47 + Description: '' + conversion: + factor: 1.0 + base_units: + - D47 +- Status: '' + LevelAndCategory: '1' + Name: volt per kelvin + ConversionFactor: V/K + Symbol: V/K + CommonCode: D48 + Description: '' + conversion: + factor: 1.0 + base_units: + - D48 +- Status: '' + LevelAndCategory: 1S + Name: millivolt per kelvin + ConversionFactor: 10⁻³ V/K + Symbol: mV/K + CommonCode: D49 + Description: '' + conversion: + factor: 0.001 + base_units: + - D48 +- Status: '' + LevelAndCategory: '2' + Name: kilogram per square centimetre + ConversionFactor: 10⁴ kg/m² + Symbol: kg/cm² + CommonCode: D5 + Description: '' + conversion: + factor: 10000.0 + base_units: + - '28' +- Status: '' + LevelAndCategory: '1' + Name: volt per metre + ConversionFactor: V/m + Symbol: V/m + CommonCode: D50 + Description: '' + conversion: + factor: 1.0 + base_units: + - D50 +- Status: '' + LevelAndCategory: 1S + Name: volt per millimetre + ConversionFactor: 10³ V/m + Symbol: V/mm + CommonCode: D51 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D50 +- Status: '' + LevelAndCategory: '1' + Name: watt per kelvin + ConversionFactor: W/K + Symbol: W/K + CommonCode: D52 + Description: '' + conversion: + factor: 1.0 + base_units: + - D52 +- Status: '' + LevelAndCategory: '1' + Name: watt per metre kelvin + ConversionFactor: W/(m x K) + Symbol: W/(m·K) + CommonCode: D53 + Description: '' + conversion: + factor: 1.0 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '1' + Name: watt per square metre + ConversionFactor: W/m² + Symbol: W/m² + CommonCode: D54 + Description: '' + conversion: + factor: 1.0 + base_units: + - D54 +- Status: '' + LevelAndCategory: '1' + Name: watt per square metre kelvin + ConversionFactor: W/(m² x K) + Symbol: W/(m²·K) + CommonCode: D55 + Description: '' + conversion: + factor: 1.0 + base_units: + - D55 +- Status: '' + LevelAndCategory: '1' + Name: watt per square metre kelvin to the fourth power + ConversionFactor: W/(m² x K⁴) + Symbol: W/(m²·K⁴) + CommonCode: D56 + Description: '' + conversion: + factor: 1.0 + base_units: + - D56 +- Status: '' + LevelAndCategory: '1' + Name: watt per steradian + ConversionFactor: W/sr + Symbol: W/sr + CommonCode: D57 + Description: '' + conversion: + factor: 1.0 + base_units: + - D57 +- Status: '' + LevelAndCategory: '1' + Name: watt per steradian square metre + ConversionFactor: W/(sr x m²) + Symbol: W/(sr·m²) + CommonCode: D58 + Description: '' + conversion: + factor: 1.0 + base_units: + - D58 +- Status: '' + LevelAndCategory: '1' + Name: weber per metre + ConversionFactor: Wb/m + Symbol: Wb/m + CommonCode: D59 + Description: '' + conversion: + factor: 1.0 + base_units: + - D59 +- Status: '' + LevelAndCategory: '2' + Name: roentgen per second + ConversionFactor: 2,58 x 10⁻⁴ C/(kg x s) + Symbol: R/s + CommonCode: D6 + Description: '' + conversion: + factor: 0.000258 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: weber per millimetre + ConversionFactor: 10³ Wb/m + Symbol: Wb/mm + CommonCode: D60 + Description: '' + conversion: + factor: 1000.0 + base_units: + - D59 +- Status: '' + LevelAndCategory: '1' + Name: minute [unit of angle] + ConversionFactor: 2,908 882 x 10⁻⁴ rad + Symbol: "'" + CommonCode: D61 + Description: '' + conversion: + factor: 0.0002908882 + base_units: + - C81 +- Status: '' + LevelAndCategory: '1' + Name: second [unit of angle] + ConversionFactor: 4,848 137 x 10⁻⁶ rad + Symbol: "\"" + CommonCode: D62 + Description: '' + conversion: + factor: 4.848137e-06 + base_units: + - C81 +- Status: '' + LevelAndCategory: '3.9' + Name: book + ConversionFactor: '' + Symbol: '' + CommonCode: D63 + Description: 'A unit of count defining the number of books (book: set of items bound + together or written document of a material whole).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: block + ConversionFactor: '' + Symbol: '' + CommonCode: D64 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: round + ConversionFactor: '' + Symbol: '' + CommonCode: D65 + Description: 'A unit of count defining the number of rounds (round: A circular or + cylindrical object).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: cassette + ConversionFactor: '' + Symbol: '' + CommonCode: D66 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: dollar per hour + ConversionFactor: '' + Symbol: '' + CommonCode: D67 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: number of words + ConversionFactor: '' + Symbol: '' + CommonCode: D68 + Description: A unit of count defining the number of words. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: inch to the fourth power + ConversionFactor: 41,623 14 x 10⁻⁸ m⁴ + Symbol: in⁴ + CommonCode: D69 + Description: '' + conversion: + factor: 4.162314e-07 + base_units: + - B83 +- Status: X + LevelAndCategory: '3.9' + Name: sandwich + ConversionFactor: '' + Symbol: '' + CommonCode: D7 + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: calorie (international table) + ConversionFactor: 4,186 8 J + Symbol: calIT + CommonCode: D70 + Description: '' + conversion: + factor: 4.1868 + base_units: + - JOU +- Status: D + LevelAndCategory: '2' + Name: calorie (international table) per second centimetre kelvin + ConversionFactor: 418,68 W/(m x K) + Symbol: calIT/(s·cm·K) + CommonCode: D71 + Description: '' + conversion: + factor: 418.68 + base_units: + - D53 + - N80 +- Status: D + LevelAndCategory: '2' + Name: calorie (international table) per second square centimetre kelvin + ConversionFactor: 4,186 8 x 10⁴ W/(m² x K) + Symbol: calIT/(s·cm²·K) + CommonCode: D72 + Description: '' + conversion: + factor: 41868.0 + base_units: + - D55 +- Status: '' + LevelAndCategory: '1' + Name: joule square metre + ConversionFactor: J x m² + Symbol: J·m² + CommonCode: D73 + Description: '' + conversion: + factor: 1.0 + base_units: + - D73 +- Status: '' + LevelAndCategory: '1' + Name: kilogram per mole + ConversionFactor: kg/mol + Symbol: kg/mol + CommonCode: D74 + Description: '' + conversion: + factor: 1.0 + base_units: + - D74 +- Status: D + LevelAndCategory: '2' + Name: calorie (international table) per gram + ConversionFactor: 4 186,8 J/kg + Symbol: calIT/g + CommonCode: D75 + Description: '' + conversion: + factor: 4186.8 + base_units: + - J2 +- Status: D + LevelAndCategory: '2' + Name: calorie (international table) per gram kelvin + ConversionFactor: 4 186,8 J/(kg x K) + Symbol: calIT/(g·K) + CommonCode: D76 + Description: '' + conversion: + factor: 4186.8 + base_units: + - B11 +- Status: '' + LevelAndCategory: 1S + Name: megacoulomb + ConversionFactor: 10⁶ C + Symbol: MC + CommonCode: D77 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - A8 +- Status: '' + LevelAndCategory: '3.1' + Name: megajoule per second + ConversionFactor: '' + Symbol: MJ/s + CommonCode: D78 + Description: A unit of accumulated energy equal to one million joules per second. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: beam + ConversionFactor: '' + Symbol: '' + CommonCode: D79 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: draize score + ConversionFactor: '' + Symbol: '' + CommonCode: D8 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: microwatt + ConversionFactor: 10⁻⁶ W + Symbol: µW + CommonCode: D80 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1S + Name: microtesla + ConversionFactor: 10⁻⁶ T + Symbol: µT + CommonCode: D81 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D33 +- Status: '' + LevelAndCategory: 1S + Name: microvolt + ConversionFactor: 10⁻⁶ V + Symbol: µV + CommonCode: D82 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: 1S + Name: millinewton metre + ConversionFactor: 10⁻³ N x m + Symbol: mN·m + CommonCode: D83 + Description: '' + conversion: + factor: 0.001 + base_units: + - NU +- Status: '' + LevelAndCategory: 1S + Name: microwatt per square metre + ConversionFactor: 10⁻⁶ W/m² + Symbol: µW/m² + CommonCode: D85 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D54 +- Status: '' + LevelAndCategory: 1S + Name: millicoulomb + ConversionFactor: 10⁻³ C + Symbol: mC + CommonCode: D86 + Description: '' + conversion: + factor: 0.001 + base_units: + - A8 +- Status: '' + LevelAndCategory: 1S + Name: millimole per kilogram + ConversionFactor: 10⁻³ mol/kg + Symbol: mmol/kg + CommonCode: D87 + Description: '' + conversion: + factor: 0.001 + base_units: + - C19 +- Status: '' + LevelAndCategory: 1S + Name: millicoulomb per cubic metre + ConversionFactor: 10⁻³ C/m³ + Symbol: mC/m³ + CommonCode: D88 + Description: '' + conversion: + factor: 0.001 + base_units: + - A29 +- Status: '' + LevelAndCategory: 1S + Name: millicoulomb per square metre + ConversionFactor: 10⁻³ C/m² + Symbol: mC/m² + CommonCode: D89 + Description: '' + conversion: + factor: 0.001 + base_units: + - A34 +- Status: D + LevelAndCategory: '2,3.9' + Name: dyne per square centimetre + ConversionFactor: 10⁻¹ Pa + Symbol: dyn/cm² + CommonCode: D9 + Description: '' + conversion: + factor: 0.1 + base_units: + - C55 + - PAL +- Status: X + LevelAndCategory: '3.1' + Name: cubic metre (net) + ConversionFactor: '' + Symbol: '' + CommonCode: D90 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: rem + ConversionFactor: 10⁻² Sv + Symbol: rem + CommonCode: D91 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: band + ConversionFactor: '' + Symbol: '' + CommonCode: D92 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: second per cubic metre + ConversionFactor: s/m³ + Symbol: s/m³ + CommonCode: D93 + Description: '' + conversion: + factor: 1.0 + base_units: + - D93 +- Status: '' + LevelAndCategory: '1' + Name: second per cubic metre radian + ConversionFactor: s/(rad x m³) + Symbol: s/(rad·m³) + CommonCode: D94 + Description: '' + conversion: + factor: 1.0 + base_units: + - D94 +- Status: '' + LevelAndCategory: 1S + Name: joule per gram + ConversionFactor: J/(10⁻³ x kg) + Symbol: J/g + CommonCode: D95 + Description: '' + conversion: + factor: 1.0 + base_units: + - D95 +- Status: X + LevelAndCategory: '3.1' + Name: pound gross + ConversionFactor: '' + Symbol: '' + CommonCode: D96 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: pallet/unit load + ConversionFactor: '' + Symbol: '' + CommonCode: D97 + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: mass pound + ConversionFactor: '' + Symbol: '' + CommonCode: D98 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: sleeve + ConversionFactor: '' + Symbol: '' + CommonCode: D99 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: decare + ConversionFactor: 10³ m² + Symbol: daa + CommonCode: DAA + Description: '' + conversion: + factor: 1000.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: '3.2' + Name: ten day + ConversionFactor: '' + Symbol: '' + CommonCode: DAD + Description: A unit of time defining the number of days in multiples of 10. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: day + ConversionFactor: 86 400 s + Symbol: d + CommonCode: DAY + Description: '' + conversion: + factor: 86400.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.1' + Name: dry pound + ConversionFactor: '' + Symbol: '' + CommonCode: DB + Description: A unit of mass defining the number of pounds of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: disk (disc) + ConversionFactor: '' + Symbol: '' + CommonCode: DC + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: degree [unit of angle] + ConversionFactor: 1,745 329 x 10⁻² rad + Symbol: "°" + CommonCode: DD + Description: '' + conversion: + factor: 0.01745329 + base_units: + - C81 +- Status: X + LevelAndCategory: '3.9' + Name: deal + ConversionFactor: '' + Symbol: '' + CommonCode: DE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: decade + ConversionFactor: '' + Symbol: '' + CommonCode: DEC + Description: 'A unit of count defining the number of decades (decade: quantity equal + to 10 or time equal to 10 years).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: decigram + ConversionFactor: 10⁻⁴ kg + Symbol: dg + CommonCode: DG + Description: '' + conversion: + factor: 0.0001 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.3' + Name: dispenser + ConversionFactor: '' + Symbol: '' + CommonCode: DI + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: decagram + ConversionFactor: 10⁻² kg + Symbol: dag + CommonCode: DJ + Description: '' + conversion: + factor: 0.01 + base_units: + - KGM +- Status: '' + LevelAndCategory: 1M + Name: decilitre + ConversionFactor: 10⁻⁴ m³ + Symbol: dl + CommonCode: DLT + Description: '' + conversion: + factor: 0.0001 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: cubic decametre + ConversionFactor: 10³ m³ + Symbol: dam³ + CommonCode: DMA + Description: '' + conversion: + factor: 1000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: square decimetre + ConversionFactor: 10⁻² m² + Symbol: dm² + CommonCode: DMK + Description: '' + conversion: + factor: 0.01 + base_units: + - MTK +- Status: '' + LevelAndCategory: '3.1' + Name: standard kilolitre + ConversionFactor: '' + Symbol: '' + CommonCode: DMO + Description: A unit of volume defining the number of kilolitres of a product at + a temperature of 15 degrees Celsius, especially in relation to hydrocarbon oils. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre + ConversionFactor: 10⁻³ m³ + Symbol: dm³ + CommonCode: DMQ + Description: '' + conversion: + factor: 0.001 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: decimetre + ConversionFactor: 10⁻¹ m + Symbol: dm + CommonCode: DMT + Description: '' + conversion: + factor: 0.1 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1S + Name: decinewton metre + ConversionFactor: 10⁻¹ N x m + Symbol: dN·m + CommonCode: DN + Description: '' + conversion: + factor: 0.1 + base_units: + - NU +- Status: '' + LevelAndCategory: '3.2' + Name: dozen piece + ConversionFactor: '' + Symbol: '' + CommonCode: DPC + Description: 'A unit of count defining the number of pieces in multiples of 12 (piece: + a single item, article or exemplar).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.2' + Name: dozen pair + ConversionFactor: '' + Symbol: '' + CommonCode: DPR + Description: 'A unit of count defining the number of pairs in multiples of 12 (pair: + item described by two''s).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: displacement tonnage + ConversionFactor: '' + Symbol: '' + CommonCode: DPT + Description: A unit of mass defining the volume of sea water a ship displaces, expressed + as the number of tons. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.6' + Name: data record + ConversionFactor: '' + Symbol: '' + CommonCode: DQ + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: drum + ConversionFactor: '' + Symbol: '' + CommonCode: DR + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: dram (US) + ConversionFactor: 3,887 935 g + Symbol: '' + CommonCode: DRA + Description: 'Synonym: drachm (UK), troy dram' + conversion: + factor: 3.887935 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: dram (UK) + ConversionFactor: 1,771 745 g + Symbol: '' + CommonCode: DRI + Description: 'Synonym: avoirdupois dram' + conversion: + factor: 1.771745 + base_units: [] +- Status: '' + LevelAndCategory: '3.2' + Name: dozen roll + ConversionFactor: '' + Symbol: '' + CommonCode: DRL + Description: A unit of count defining the number of rolls, expressed in twelve roll + units. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: drachm (UK) + ConversionFactor: 3,887 935 g + Symbol: '' + CommonCode: DRM + Description: '' + conversion: + factor: 3.887935 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: display + ConversionFactor: '' + Symbol: '' + CommonCode: DS + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: dry ton + ConversionFactor: '' + Symbol: '' + CommonCode: DT + Description: A unit of mass defining the number of tons of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M,3.5 + Name: decitonne + ConversionFactor: 10² kg + Symbol: dt or dtn + CommonCode: DTN + Description: 'Synonym: centner, metric 100 kg; quintal, metric 100 kg' + conversion: + factor: 100.0 + base_units: + - KGM +- Status: D + LevelAndCategory: '2' + Name: dyne + ConversionFactor: 10⁻⁵ N + Symbol: dyn + CommonCode: DU + Description: '' + conversion: + factor: 1.0e-05 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: pennyweight + ConversionFactor: 1,555 174 g + Symbol: '' + CommonCode: DWT + Description: '' + conversion: + factor: 1.555174 + base_units: [] +- Status: D + LevelAndCategory: '2' + Name: dyne per centimetre + ConversionFactor: 10⁻³ N/m + Symbol: dyn/cm + CommonCode: DX + Description: '' + conversion: + factor: 0.001 + base_units: + - 4P +- Status: X + LevelAndCategory: '3.9' + Name: directory book + ConversionFactor: '' + Symbol: '' + CommonCode: DY + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: dozen + ConversionFactor: '12' + Symbol: DOZ + CommonCode: DZN + Description: A unit of count defining the number of units in multiples of 12. + conversion: + factor: 12.0 +- Status: '' + LevelAndCategory: '3.2' + Name: dozen pack + ConversionFactor: '' + Symbol: '' + CommonCode: DZP + Description: 'A unit of count defining the number of packs in multiples of 12 (pack: + standard packaging unit).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: newton per square centimetre + ConversionFactor: 10⁴ Pa + Symbol: N/cm² + CommonCode: E01 + Description: A measure of pressure expressed in newtons per square centimetre. + conversion: + factor: 10000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.1' + Name: megawatt hour per hour + ConversionFactor: '' + Symbol: MW·h/h + CommonCode: E07 + Description: A unit of accumulated energy of a million watts over a period of one + hour. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: megawatt per hertz + ConversionFactor: '' + Symbol: MW/Hz + CommonCode: E08 + Description: A unit of energy expressed as the load change in million watts that + will cause a frequency shift of one hertz. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: milliampere hour + ConversionFactor: 3,6 C + Symbol: mA·h + CommonCode: E09 + Description: A unit of power load delivered at the rate of one thousandth of an + ampere over a period of one hour. + conversion: + factor: 3.6 + base_units: + - A8 +- Status: '' + LevelAndCategory: '3.5' + Name: degree day + ConversionFactor: '' + Symbol: deg da + CommonCode: E10 + Description: A unit of measure used in meteorology and engineering to measure the + demand for heating or cooling over a given period of days. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.5' + Name: gigacalorie + ConversionFactor: 10⁹ cal + Symbol: '' + CommonCode: E11 + Description: A unit of heat energy equal to one thousand million calories. + conversion: + factor: 1000000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.9' + Name: mille + ConversionFactor: '' + Symbol: '' + CommonCode: E12 + Description: A unit of count defining the number of cigarettes in units of 1000. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (international table) + ConversionFactor: 4,186 8 x 10³ J + Symbol: kcalIT + CommonCode: E14 + Description: A unit of heat energy equal to one thousand calories. + conversion: + factor: 4186.8 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (thermochemical) per hour + ConversionFactor: 1,162 22 W + Symbol: kcalth/h + CommonCode: E15 + Description: A unit of energy equal to one thousand calories per hour. + conversion: + factor: 1.16222 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.1' + Name: million Btu(IT) per hour + ConversionFactor: 293 071,1 W + Symbol: BtuIT/h + CommonCode: E16 + Description: A unit of power equal to one million British thermal units per hour. + conversion: + factor: 293071.1 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.1' + Name: cubic foot per second + ConversionFactor: 2,831 685 x 10⁻² m³/s + Symbol: ft³/s + CommonCode: E17 + Description: A unit of volume equal to one cubic foot passing a given point in a + period of one second. + conversion: + factor: 0.02831685 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: tonne per hour + ConversionFactor: 2,777 78 x 10⁻¹ kg/s + Symbol: t/h + CommonCode: E18 + Description: A unit of weight or mass equal to one tonne per hour. + conversion: + factor: 0.277778 + base_units: + - KGS +- Status: '' + LevelAndCategory: '3.1' + Name: ping + ConversionFactor: 3,305 m² + Symbol: '' + CommonCode: E19 + Description: A unit of area equal to 3.3 square metres. + conversion: + factor: 3.305 + base_units: + - MTK +- Status: X + LevelAndCategory: '3.9' + Name: belt + ConversionFactor: '' + Symbol: '' + CommonCode: E2 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: megabit per second + ConversionFactor: '' + Symbol: Mbit/s + CommonCode: E20 + Description: A unit of information equal to 10⁶ (1000000) bits (binary digits) per + second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: shares + ConversionFactor: '' + Symbol: '' + CommonCode: E21 + Description: 'A unit of count defining the number of shares (share: a total or portion + of the parts into which a business entity’s capital is divided).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: TEU + ConversionFactor: '' + Symbol: '' + CommonCode: E22 + Description: A unit of count defining the number of twenty-foot equivalent units + (TEUs) as a measure of containerized cargo capacity. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: tyre + ConversionFactor: '' + Symbol: '' + CommonCode: E23 + Description: A unit of count defining the number of tyres (a solid or air-filled + covering placed around a wheel rim to form a soft contact with the road, absorb + shock and provide traction). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: active unit + ConversionFactor: '' + Symbol: '' + CommonCode: E25 + Description: A unit of count defining the number of active units within a substance. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: dose + ConversionFactor: '' + Symbol: '' + CommonCode: E27 + Description: 'A unit of count defining the number of doses (dose: a definite quantity + of a medicine or drug).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: air dry ton + ConversionFactor: '' + Symbol: '' + CommonCode: E28 + Description: A unit of mass defining the number of tons of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: trailer + ConversionFactor: '' + Symbol: '' + CommonCode: E3 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: strand + ConversionFactor: '' + Symbol: '' + CommonCode: E30 + Description: 'A unit of count defining the number of strands (strand: long, thin, + flexible, single thread, strip of fibre, constituent filament or multiples of + the same, twisted together).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: square metre per litre + ConversionFactor: '' + Symbol: m²/l + CommonCode: E31 + Description: A unit of count defining the number of square metres per litre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: litre per hour + ConversionFactor: 2,777 78 x 10⁻⁷ m³/s + Symbol: l/h + CommonCode: E32 + Description: A unit of count defining the number of litres per hour. + conversion: + factor: 2.77778e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '3.1' + Name: foot per thousand + ConversionFactor: 3,048 x 10⁻⁴ m + Symbol: '' + CommonCode: E33 + Description: A unit of count defining the number of feet per thousand units. + conversion: + factor: 0.0003048 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.6' + Name: gigabyte + ConversionFactor: '' + Symbol: Gbyte + CommonCode: E34 + Description: A unit of information equal to 10⁹ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: terabyte + ConversionFactor: '' + Symbol: Tbyte + CommonCode: E35 + Description: A unit of information equal to 10¹² bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: petabyte + ConversionFactor: '' + Symbol: Pbyte + CommonCode: E36 + Description: A unit of information equal to 10¹⁵ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: pixel + ConversionFactor: '' + Symbol: '' + CommonCode: E37 + Description: 'A unit of count defining the number of pixels (pixel: picture element).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: megapixel + ConversionFactor: '' + Symbol: '' + CommonCode: E38 + Description: A unit of count equal to 10⁶ (1000000) pixels (picture elements). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: dots per inch + ConversionFactor: '' + Symbol: dpi + CommonCode: E39 + Description: A unit of information defining the number of dots per linear inch as + a measure of the resolution or sharpness of a graphic image. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: gross kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: E4 + Description: A unit of mass defining the total number of kilograms before deductions. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: part per hundred thousand + ConversionFactor: 1 x 10⁻⁵ + Symbol: ppht + CommonCode: E40 + Description: A unit of proportion equal to 10⁻⁵. + conversion: + factor: 1.0e-05 +- Status: '' + LevelAndCategory: '2' + Name: kilogram-force per square millimetre + ConversionFactor: 9,806 65 x 10⁶ Pa + Symbol: kgf/mm² + CommonCode: E41 + Description: A unit of pressure defining the number of kilograms force per square + millimetre. + conversion: + factor: 9806650.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: kilogram-force per square centimetre + ConversionFactor: 9,806 65 x 10⁴ Pa + Symbol: kgf/cm² + CommonCode: E42 + Description: A unit of pressure defining the number of kilograms force per square + centimetre. + conversion: + factor: 98066.5 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1M + Name: joule per square centimetre + ConversionFactor: 10⁴ J/m² + Symbol: J/cm² + CommonCode: E43 + Description: A unit of energy defining the number of joules per square centimetre. + conversion: + factor: 10000.0 + base_units: + - B13 +- Status: '' + LevelAndCategory: '3.5' + Name: kilogram-force metre per square centimetre + ConversionFactor: '' + Symbol: kgf·m/cm² + CommonCode: E44 + Description: A unit of torsion defining the torque kilogram-force metre per square + centimetre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: milliohm + ConversionFactor: 10⁻³ Ω + Symbol: mΩ + CommonCode: E45 + Description: '' + conversion: + factor: 0.001 + base_units: + - OHM +- Status: '' + LevelAndCategory: '3.1' + Name: kilowatt hour per cubic metre + ConversionFactor: 3,6 x 10⁶ J/m³ + Symbol: kW·h/m³ + CommonCode: E46 + Description: A unit of energy consumption expressed as kilowatt hour per cubic metre. + conversion: + factor: 3600000.0 + base_units: + - B8 +- Status: '' + LevelAndCategory: '3.1' + Name: kilowatt hour per kelvin + ConversionFactor: 3,6 x 10⁶ J/K + Symbol: kW·h/K + CommonCode: E47 + Description: A unit of energy consumption expressed as kilowatt hour per kelvin. + conversion: + factor: 3600000.0 + base_units: + - JE +- Status: '' + LevelAndCategory: '3.5' + Name: service unit + ConversionFactor: '' + Symbol: '' + CommonCode: E48 + Description: 'A unit of count defining the number of service units (service unit: + defined period / property / facility / utility of supply).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: working day + ConversionFactor: '' + Symbol: '' + CommonCode: E49 + Description: 'A unit of count defining the number of working days (working day: + a day on which work is ordinarily performed).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: metric long ton + ConversionFactor: '' + Symbol: '' + CommonCode: E5 + Description: Use ton (UK) or long ton (US) (common code LTN) + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: accounting unit + ConversionFactor: '' + Symbol: '' + CommonCode: E50 + Description: A unit of count defining the number of accounting units. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: job + ConversionFactor: '' + Symbol: '' + CommonCode: E51 + Description: A unit of count defining the number of jobs. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: run foot + ConversionFactor: '' + Symbol: '' + CommonCode: E52 + Description: A unit of count defining the number feet per run. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: test + ConversionFactor: '' + Symbol: '' + CommonCode: E53 + Description: A unit of count defining the number of tests. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: trip + ConversionFactor: '' + Symbol: '' + CommonCode: E54 + Description: A unit of count defining the number of trips. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: use + ConversionFactor: '' + Symbol: '' + CommonCode: E55 + Description: A unit of count defining the number of times an object is used. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: well + ConversionFactor: '' + Symbol: '' + CommonCode: E56 + Description: A unit of count defining the number of wells. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: zone + ConversionFactor: '' + Symbol: '' + CommonCode: E57 + Description: A unit of count defining the number of zones. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: exabit per second + ConversionFactor: '' + Symbol: Ebit/s + CommonCode: E58 + Description: A unit of information equal to 10¹⁸ bits (binary digits) per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: exbibyte + ConversionFactor: '' + Symbol: Eibyte + CommonCode: E59 + Description: A unit of information equal to 2⁶⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: pebibyte + ConversionFactor: '' + Symbol: Pibyte + CommonCode: E60 + Description: A unit of information equal to 2⁵⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: tebibyte + ConversionFactor: '' + Symbol: Tibyte + CommonCode: E61 + Description: A unit of information equal to 2⁴⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gibibyte + ConversionFactor: '' + Symbol: Gibyte + CommonCode: E62 + Description: A unit of information equal to 2³⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: mebibyte + ConversionFactor: '' + Symbol: Mibyte + CommonCode: E63 + Description: A unit of information equal to 2²⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: kibibyte + ConversionFactor: '' + Symbol: Kibyte + CommonCode: E64 + Description: A unit of information equal to 2¹⁰ bytes. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: exbibit per metre + ConversionFactor: '' + Symbol: Eibit/m + CommonCode: E65 + Description: A unit of information equal to 2⁶⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: exbibit per square metre + ConversionFactor: '' + Symbol: Eibit/m² + CommonCode: E66 + Description: A unit of information equal to 2⁶⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: exbibit per cubic metre + ConversionFactor: '' + Symbol: Eibit/m³ + CommonCode: E67 + Description: A unit of information equal to 2⁶⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gigabyte per second + ConversionFactor: '' + Symbol: Gbyte/s + CommonCode: E68 + Description: A unit of information equal to 10⁹ bytes per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gibibit per metre + ConversionFactor: '' + Symbol: Gibit/m + CommonCode: E69 + Description: A unit of information equal to 2³⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gibibit per square metre + ConversionFactor: '' + Symbol: Gibit/m² + CommonCode: E70 + Description: A unit of information equal to 2³⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: gibibit per cubic metre + ConversionFactor: '' + Symbol: Gibit/m³ + CommonCode: E71 + Description: A unit of information equal to 2³⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: kibibit per metre + ConversionFactor: '' + Symbol: Kibit/m + CommonCode: E72 + Description: A unit of information equal to 2¹⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: kibibit per square metre + ConversionFactor: '' + Symbol: Kibit/m² + CommonCode: E73 + Description: A unit of information equal to 2¹⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: kibibit per cubic metre + ConversionFactor: '' + Symbol: Kibit/m³ + CommonCode: E74 + Description: A unit of information equal to 2¹⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: mebibit per metre + ConversionFactor: '' + Symbol: Mibit/m + CommonCode: E75 + Description: A unit of information equal to 2²⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: mebibit per square metre + ConversionFactor: '' + Symbol: Mibit/m² + CommonCode: E76 + Description: A unit of information equal to 2²⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: mebibit per cubic metre + ConversionFactor: '' + Symbol: Mibit/m³ + CommonCode: E77 + Description: A unit of information equal to 2²⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: petabit + ConversionFactor: '' + Symbol: Pbit + CommonCode: E78 + Description: A unit of information equal to 10¹⁵ bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: petabit per second + ConversionFactor: '' + Symbol: Pbit/s + CommonCode: E79 + Description: A unit of information equal to 10¹⁵ bits (binary digits) per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: pebibit per metre + ConversionFactor: '' + Symbol: Pibit/m + CommonCode: E80 + Description: A unit of information equal to 2⁵⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: pebibit per square metre + ConversionFactor: '' + Symbol: Pibit/m² + CommonCode: E81 + Description: A unit of information equal to 2⁵⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: pebibit per cubic metre + ConversionFactor: '' + Symbol: Pibit/m³ + CommonCode: E82 + Description: A unit of information equal to 2⁵⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: terabit + ConversionFactor: '' + Symbol: Tbit + CommonCode: E83 + Description: A unit of information equal to 10¹² bits (binary digits). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: terabit per second + ConversionFactor: '' + Symbol: Tbit/s + CommonCode: E84 + Description: A unit of information equal to 10¹² bits (binary digits) per second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: tebibit per metre + ConversionFactor: '' + Symbol: Tibit/m + CommonCode: E85 + Description: A unit of information equal to 2⁴⁰ bits (binary digits) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: tebibit per cubic metre + ConversionFactor: '' + Symbol: Tibit/m³ + CommonCode: E86 + Description: A unit of information equal to 2⁴⁰ bits (binary digits) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: tebibit per square metre + ConversionFactor: '' + Symbol: Tibit/m² + CommonCode: E87 + Description: A unit of information equal to 2⁴⁰ bits (binary digits) per square + metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: bit per metre + ConversionFactor: '' + Symbol: bit/m + CommonCode: E88 + Description: A unit of information equal to 1 bit (binary digit) per metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: bit per square metre + ConversionFactor: '' + Symbol: bit/m² + CommonCode: E89 + Description: A unit of information equal to 1 bit (binary digit) per square metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: reciprocal centimetre + ConversionFactor: 10² m⁻¹ + Symbol: cm⁻¹ + CommonCode: E90 + Description: '' + conversion: + factor: 100.0 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.1' + Name: reciprocal day + ConversionFactor: 1,157 41 × 10⁻⁵ s⁻¹ + Symbol: d⁻¹ + CommonCode: E91 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per hour + ConversionFactor: 2,777 78 × 10⁻⁷ m³ x s⁻¹ + Symbol: dm³/h + CommonCode: E92 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilogram per hour + ConversionFactor: 2,777 78 × 10⁻⁴ kg x s⁻¹ + Symbol: kg/h + CommonCode: E93 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilomole per second + ConversionFactor: 10³ s⁻¹ x mol + Symbol: kmol/s + CommonCode: E94 + Description: '' + conversion: + factor: 1000.0 + base_units: + - KAT +- Status: '' + LevelAndCategory: 1S + Name: mole per second + ConversionFactor: s⁻¹ x mol + Symbol: mol/s + CommonCode: E95 + Description: '' + conversion: + factor: 1.0 + base_units: + - E95 +- Status: '' + LevelAndCategory: 1M + Name: degree per second + ConversionFactor: 1,745 329 x 10⁻² rad x s⁻¹ + Symbol: "°/s" + CommonCode: E96 + Description: '' + conversion: + factor: 0.01745329 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millimetre per degree Celcius metre + ConversionFactor: 10⁻³ K⁻¹ + Symbol: mm/(°C·m) + CommonCode: E97 + Description: '' + conversion: + factor: 0.001 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: 1M + Name: degree Celsius per kelvin + ConversionFactor: '1.0' + Symbol: "°C/K" + CommonCode: E98 + Description: '' + conversion: + factor: 1.0 + base_units: + - E98 + - F02 + - H60 + - L52 + - M91 +- Status: '' + LevelAndCategory: 1M + Name: hectopascal per bar + ConversionFactor: 10⁻³ + Symbol: hPa/bar + CommonCode: E99 + Description: '' + conversion: + factor: 0.001 +- Status: '' + LevelAndCategory: '3.2' + Name: each + ConversionFactor: '' + Symbol: '' + CommonCode: EA + Description: A unit of count defining the number of items regarded as separate units. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: electronic mail box + ConversionFactor: '' + Symbol: '' + CommonCode: EB + Description: A unit of count defining the number of electronic mail boxes. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: each per month + ConversionFactor: '' + Symbol: '' + CommonCode: EC + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.2' + Name: eleven pack + ConversionFactor: '' + Symbol: '' + CommonCode: EP + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: equivalent gallon + ConversionFactor: '' + Symbol: '' + CommonCode: EQ + Description: A unit of volume defining the number of gallons of product produced + from concentrate. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: envelope + ConversionFactor: '' + Symbol: '' + CommonCode: EV + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: bit per cubic metre + ConversionFactor: '' + Symbol: bit/m³ + CommonCode: F01 + Description: A unit of information equal to 1 bit (binary digit) per cubic metre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kelvin per kelvin + ConversionFactor: '1.0' + Symbol: K/K + CommonCode: F02 + Description: '' + conversion: + factor: 1.0 + base_units: + - E98 + - F02 + - H60 + - L52 + - M91 +- Status: '' + LevelAndCategory: 1M + Name: kilopascal per bar + ConversionFactor: 10⁻² + Symbol: kPa/bar + CommonCode: F03 + Description: '' + conversion: + factor: 0.01 +- Status: '' + LevelAndCategory: 1M + Name: millibar per bar + ConversionFactor: 10⁻³ + Symbol: mbar/bar + CommonCode: F04 + Description: '' + conversion: + factor: 0.001 +- Status: '' + LevelAndCategory: 1M + Name: megapascal per bar + ConversionFactor: 10¹ + Symbol: MPa/bar + CommonCode: F05 + Description: '' + conversion: + factor: 10.0 +- Status: '' + LevelAndCategory: '2' + Name: poise per bar + ConversionFactor: 10⁻⁶ s + Symbol: P/bar + CommonCode: F06 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: pascal per bar + ConversionFactor: 10⁻⁵ + Symbol: Pa/bar + CommonCode: F07 + Description: '' + conversion: + factor: 1.0e-05 +- Status: '' + LevelAndCategory: '2' + Name: milliampere per inch + ConversionFactor: 3,937 007 874 015 75 x 10⁻² A x m⁻¹ + Symbol: mA/in + CommonCode: F08 + Description: '' + conversion: + factor: 0.0393700787401575 + base_units: [] +- Status: X + LevelAndCategory: '3.8' + Name: thousand cubic foot per day + ConversionFactor: '' + Symbol: '' + CommonCode: F1 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kelvin per hour + ConversionFactor: 2,777 78 × 10⁻⁴ s⁻¹ x K + Symbol: K/h + CommonCode: F10 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kelvin per minute + ConversionFactor: 1,666 67 × 10⁻² s⁻¹ x K + Symbol: K/min + CommonCode: F11 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kelvin per second + ConversionFactor: s⁻¹ x K + Symbol: K/s + CommonCode: F12 + Description: '' + conversion: + factor: 1.0 + base_units: + - F12 +- Status: '' + LevelAndCategory: '2' + Name: slug + ConversionFactor: 1,459 390 x 10¹ kg + Symbol: slug + CommonCode: F13 + Description: A unit of mass. One slug is the mass accelerated at 1 foot per second + per second by a force of 1 pound. + conversion: + factor: 14.5939 + base_units: + - KGM +- Status: '' + LevelAndCategory: 1M + Name: gram per kelvin + ConversionFactor: 10⁻³ kg x K⁻¹ + Symbol: g/K + CommonCode: F14 + Description: '' + conversion: + factor: 0.001 + base_units: + - F15 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per kelvin + ConversionFactor: kg x K⁻¹ + Symbol: kg/K + CommonCode: F15 + Description: '' + conversion: + factor: 1.0 + base_units: + - F15 +- Status: '' + LevelAndCategory: 1M + Name: milligram per kelvin + ConversionFactor: 10⁻⁶ kg x K⁻¹ + Symbol: mg/K + CommonCode: F16 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - F15 +- Status: '' + LevelAndCategory: '2' + Name: pound-force per foot + ConversionFactor: 1,459 39 × 10¹ kg x s⁻² + Symbol: lbf/ft + CommonCode: F17 + Description: '' + conversion: + factor: 1.45939 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram square centimetre + ConversionFactor: 10⁻⁴ kg m² + Symbol: kg·cm² + CommonCode: F18 + Description: '' + conversion: + factor: 0.0001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram square millimetre + ConversionFactor: 10⁻⁶ kg m² + Symbol: kg·mm² + CommonCode: F19 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound inch squared + ConversionFactor: 2,926 397 x 10⁻⁴ kg x m² + Symbol: lb·in² + CommonCode: F20 + Description: '' + conversion: + factor: 0.0002926397 + base_units: + - B32 +- Status: '' + LevelAndCategory: '2' + Name: pound-force inch + ConversionFactor: 1,129 85 × 10⁻¹ kg x m² x s⁻² + Symbol: lbf·in + CommonCode: F21 + Description: '' + conversion: + factor: 1.12985 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound-force foot per ampere + ConversionFactor: 1,355 82 kg x m² x s⁻² x A⁻¹ + Symbol: lbf·ft/A + CommonCode: F22 + Description: '' + conversion: + factor: 1.35582 + base_units: + - F90 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic decimetre + ConversionFactor: kg x m⁻³ + Symbol: g/dm³ + CommonCode: F23 + Description: '' + conversion: + factor: 1.0 + base_units: + - F23 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per kilomol + ConversionFactor: 10⁻³ kg x mol⁻¹ + Symbol: kg/kmol + CommonCode: F24 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per hertz + ConversionFactor: 10⁻³ kg x s + Symbol: g/Hz + CommonCode: F25 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per day + ConversionFactor: 1,157 41 × 10⁻⁸ kg x s⁻¹ + Symbol: g/d + CommonCode: F26 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per hour + ConversionFactor: 2,777 78 × 10⁻⁷ kg x s⁻¹ + Symbol: g/h + CommonCode: F27 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per minute + ConversionFactor: 1,666 67 × 10⁻⁵ kg x s⁻¹ + Symbol: g/min + CommonCode: F28 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per second + ConversionFactor: 10⁻³ kg x s⁻¹ + Symbol: g/s + CommonCode: F29 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per day + ConversionFactor: 1,157 41 × 10⁻⁵ kg x s⁻¹ + Symbol: kg/d + CommonCode: F30 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per minute + ConversionFactor: 1,666 67 × 10⁻² kg x s⁻¹ + Symbol: kg/min + CommonCode: F31 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per day + ConversionFactor: 1,157 41 × 10⁻¹¹ kg x s⁻¹ + Symbol: mg/d + CommonCode: F32 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per minute + ConversionFactor: 1,666 67 × 10⁻⁸ kg x s⁻¹ + Symbol: mg/min + CommonCode: F33 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per second + ConversionFactor: 10⁻⁶ kg x s⁻¹ + Symbol: mg/s + CommonCode: F34 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per day kelvin + ConversionFactor: 1,157 41 × 10⁻⁸ kg x s⁻¹ x K⁻¹ + Symbol: g/(d·K) + CommonCode: F35 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per hour kelvin + ConversionFactor: 2,777 78 × 10⁻⁷ kg x s⁻¹ x K⁻¹ + Symbol: g/(h·K) + CommonCode: F36 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per minute kelvin + ConversionFactor: 1,666 67 × 10⁻⁵ kg x s⁻¹ x K⁻¹ + Symbol: g/(min·K) + CommonCode: F37 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per second kelvin + ConversionFactor: 10⁻³ kg x s⁻¹ x K⁻¹ + Symbol: g/(s·K) + CommonCode: F38 + Description: '' + conversion: + factor: 0.001 + base_units: + - F42 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per day kelvin + ConversionFactor: 1,157 41 × 10⁻⁵ kg x s⁻¹ x K⁻¹ + Symbol: kg/(d·K) + CommonCode: F39 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per hour kelvin + ConversionFactor: 2,777 78 × 10⁻⁴ kg x s⁻¹ x K⁻¹ + Symbol: kg/(h·K) + CommonCode: F40 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per minute kelvin + ConversionFactor: 1,666 67 × 10⁻²kg x s⁻¹ x K⁻¹ + Symbol: kg/(min·K) + CommonCode: F41 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per second kelvin + ConversionFactor: kg x s⁻¹ x K⁻¹ + Symbol: kg/(s·K) + CommonCode: F42 + Description: '' + conversion: + factor: 1.0 + base_units: + - F42 +- Status: '' + LevelAndCategory: 1M + Name: milligram per day kelvin + ConversionFactor: 1,157 41 × 10⁻¹¹ kg x s⁻¹ x K⁻¹ + Symbol: mg/(d·K) + CommonCode: F43 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per hour kelvin + ConversionFactor: 2,777 78 × 10⁻¹⁰ kg x s⁻¹ x K⁻¹ + Symbol: mg/(h·K) + CommonCode: F44 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per minute kelvin + ConversionFactor: 1,666 67 × 10⁻⁸ kg x s⁻¹ x K⁻¹ + Symbol: mg/(min·K) + CommonCode: F45 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per second kelvin + ConversionFactor: 10⁻⁶ kg x s⁻¹ x K⁻¹ + Symbol: mg/(s·K) + CommonCode: F46 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - F42 +- Status: '' + LevelAndCategory: 1M + Name: newton per millimetre + ConversionFactor: 10³ kg x s⁻² + Symbol: N/mm + CommonCode: F47 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound-force per inch + ConversionFactor: 1,751 27 × 10² kg x s⁻² + Symbol: lbf/in + CommonCode: F48 + Description: '' + conversion: + factor: 1.75127 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: rod [unit of distance] + ConversionFactor: 5,029 210 m + Symbol: rd (US) + CommonCode: F49 + Description: A unit of distance equal to 5.5 yards (16 feet 6 inches). + conversion: + factor: 5.02921 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: micrometre per kelvin + ConversionFactor: 10⁻⁶ m x K⁻¹ + Symbol: µm/K + CommonCode: F50 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - F52 +- Status: '' + LevelAndCategory: 1M + Name: centimetre per kelvin + ConversionFactor: 10⁻² m x K⁻¹ + Symbol: cm/K + CommonCode: F51 + Description: '' + conversion: + factor: 0.01 + base_units: + - F52 +- Status: '' + LevelAndCategory: 1M + Name: metre per kelvin + ConversionFactor: m x K⁻¹ + Symbol: m/K + CommonCode: F52 + Description: '' + conversion: + factor: 1.0 + base_units: + - F52 +- Status: '' + LevelAndCategory: 1M + Name: millimetre per kelvin + ConversionFactor: 10⁻³ m x K⁻¹ + Symbol: mm/K + CommonCode: F53 + Description: '' + conversion: + factor: 0.001 + base_units: + - F52 +- Status: '' + LevelAndCategory: 1M + Name: milliohm per metre + ConversionFactor: 10⁻³ Ω/m + Symbol: mΩ/m + CommonCode: F54 + Description: '' + conversion: + factor: 0.001 + base_units: + - H26 +- Status: '' + LevelAndCategory: '2' + Name: ohm per mile (statute mile) + ConversionFactor: 6,213 71 × 10⁻⁴  Ω/m + Symbol: Ω/mi + CommonCode: F55 + Description: '' + conversion: + factor: 6.21371 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: ohm per kilometre + ConversionFactor: 10⁻³ Ω/m + Symbol: Ω/km + CommonCode: F56 + Description: '' + conversion: + factor: 0.001 + base_units: + - H26 +- Status: '' + LevelAndCategory: '2' + Name: milliampere per pound-force per square inch + ConversionFactor: 1,450 38 × 10⁻⁷ kg⁻¹ x m x s² x A + Symbol: mA/(lbf/in²) + CommonCode: F57 + Description: '' + conversion: + factor: 1.45038 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: reciprocal bar + ConversionFactor: bar⁻¹ + Symbol: 1/bar + CommonCode: F58 + Description: '' + conversion: + factor: 1.0 + base_units: + - F58 +- Status: '' + LevelAndCategory: 1M + Name: milliampere per bar + ConversionFactor: 10⁻⁸ kg⁻¹ x m x s² x A + Symbol: mA/bar + CommonCode: F59 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - N93 +- Status: '' + LevelAndCategory: 1M + Name: degree Celsius per bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m x s² x K + Symbol: "°C/bar" + CommonCode: F60 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - N79 +- Status: '' + LevelAndCategory: 1M + Name: kelvin per bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m x s² x K + Symbol: K/bar + CommonCode: F61 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - N79 +- Status: '' + LevelAndCategory: 1M + Name: gram per day bar + ConversionFactor: 1,157 41 × 10⁻¹³ m x s + Symbol: g/(d·bar) + CommonCode: F62 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per hour bar + ConversionFactor: 2,777 78 × 10⁻¹² m x s + Symbol: g/(h·bar) + CommonCode: F63 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per minute bar + ConversionFactor: 1,666 67 × 10⁻¹⁰ m x s + Symbol: g/(min·bar) + CommonCode: F64 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per second bar + ConversionFactor: 10⁻⁸ m x s + Symbol: g/(s·bar) + CommonCode: F65 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - M87 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per day bar + ConversionFactor: 1,157 41 × 10⁻¹⁰ m x s + Symbol: kg/(d·bar) + CommonCode: F66 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per hour bar + ConversionFactor: 2,777 78 × 10⁻⁹ m x s + Symbol: kg/(h·bar) + CommonCode: F67 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per minute bar + ConversionFactor: 1,666 67 × 10⁻⁷ m x s + Symbol: kg/(min·bar) + CommonCode: F68 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per second bar + ConversionFactor: 10⁻⁵ m x s + Symbol: kg/(s·bar) + CommonCode: F69 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M87 +- Status: '' + LevelAndCategory: 1M + Name: milligram per day bar + ConversionFactor: 1,157 41 × 10⁻¹⁶ m x s + Symbol: mg/(d·bar) + CommonCode: F70 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per hour bar + ConversionFactor: 2,777 78 × 10⁻¹⁵ m x s + Symbol: mg/(h·bar) + CommonCode: F71 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per minute bar + ConversionFactor: 1,666 67 × 10⁻¹³ m x s + Symbol: mg/(min·bar) + CommonCode: F72 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligram per second bar + ConversionFactor: 10⁻¹¹ m x s + Symbol: mg/(s·bar) + CommonCode: F73 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - M87 +- Status: '' + LevelAndCategory: 1M + Name: gram per bar + ConversionFactor: 10⁻⁸ m x s² + Symbol: g/bar + CommonCode: F74 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - M74 +- Status: '' + LevelAndCategory: 1M + Name: milligram per bar + ConversionFactor: 10⁻¹¹ m x s² + Symbol: mg/bar + CommonCode: F75 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - M74 +- Status: '' + LevelAndCategory: 1M + Name: milliampere per millimetre + ConversionFactor: m⁻¹ x A + Symbol: mA/mm + CommonCode: F76 + Description: '' + conversion: + factor: 1.0 + base_units: + - F76 +- Status: '' + LevelAndCategory: 1M + Name: pascal second per kelvin + ConversionFactor: kg x m⁻¹ x s⁻¹ x K⁻¹ + Symbol: Pa.s/K + CommonCode: F77 + Description: '' + conversion: + factor: 1.0 + base_units: + - F77 +- Status: '' + LevelAndCategory: '2' + Name: inch of water + ConversionFactor: 2,490 89 × 10² kg x m⁻¹ x s⁻² + Symbol: inH₂O + CommonCode: F78 + Description: '' + conversion: + factor: 2.49089 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: inch of mercury + ConversionFactor: 3,386 39 × 10³ kg x m⁻¹ x s⁻² + Symbol: inHg + CommonCode: F79 + Description: '' + conversion: + factor: 3.38639 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: water horse power + ConversionFactor: 7,460 43 x 10² W + Symbol: '' + CommonCode: F80 + Description: A unit of power defining the amount of power required to move a given + volume of water against acceleration of gravity to a specified elevation (pressure + head). + conversion: + factor: 746.043 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: bar per kelvin + ConversionFactor: 10⁵ kg x m⁻¹ x s⁻² x K⁻¹ + Symbol: bar/K + CommonCode: F81 + Description: '' + conversion: + factor: 100000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: hectopascal per kelvin + ConversionFactor: 10² kg x m⁻¹ x s⁻² x K⁻¹ + Symbol: hPa/K + CommonCode: F82 + Description: '' + conversion: + factor: 100.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilopascal per kelvin + ConversionFactor: 10³ kg x m⁻¹ x s⁻² x K⁻¹ + Symbol: kPa/K + CommonCode: F83 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millibar per kelvin + ConversionFactor: 10² kg x m⁻¹ x s⁻² x K⁻¹ + Symbol: mbar/K + CommonCode: F84 + Description: '' + conversion: + factor: 100.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: megapascal per kelvin + ConversionFactor: 10⁶ kg x m⁻¹ x s⁻² x K⁻¹ + Symbol: MPa/K + CommonCode: F85 + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: poise per kelvin + ConversionFactor: 10⁻¹ kg x m⁻¹ x s⁻¹ x K⁻¹ + Symbol: P/K + CommonCode: F86 + Description: '' + conversion: + factor: 0.1 + base_units: + - F77 +- Status: '' + LevelAndCategory: 1M + Name: volt per litre minute + ConversionFactor: 1,666 67 × 10¹ kg x m⁻¹ x s⁻⁴ x A⁻¹ + Symbol: V/(l·min) + CommonCode: F87 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: newton centimetre + ConversionFactor: 10⁻² kg x m² x s⁻² + Symbol: N·cm + CommonCode: F88 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: newton metre per degree + ConversionFactor: 57,295 788 kg x m² x s⁻² x rad⁻¹ + Symbol: Nm/° + CommonCode: F89 + Description: '' + conversion: + factor: 57.295788 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: fibre per cubic centimetre of air + ConversionFactor: '' + Symbol: '' + CommonCode: F9 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: newton metre per ampere + ConversionFactor: kg x m² x s⁻² x A⁻¹ + Symbol: N·m/A + CommonCode: F90 + Description: '' + conversion: + factor: 1.0 + base_units: + - F90 +- Status: '' + LevelAndCategory: 1M + Name: bar litre per second + ConversionFactor: 10² kg x m² x s⁻³ + Symbol: bar·l/s + CommonCode: F91 + Description: '' + conversion: + factor: 100.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: bar cubic metre per second + ConversionFactor: 10⁵ kg x m² x s⁻³ + Symbol: bar·m³/s + CommonCode: F92 + Description: '' + conversion: + factor: 100000.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: hectopascal litre per second + ConversionFactor: 10⁻¹ kg x m² x s⁻³ + Symbol: hPa·l/s + CommonCode: F93 + Description: '' + conversion: + factor: 0.1 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: hectopascal cubic metre per second + ConversionFactor: 10² kg x m² x s⁻³ + Symbol: hPa·m³/s + CommonCode: F94 + Description: '' + conversion: + factor: 100.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: millibar litre per second + ConversionFactor: 10⁻¹ kg x m² x s⁻³ + Symbol: mbar·l/s + CommonCode: F95 + Description: '' + conversion: + factor: 0.1 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: millibar cubic metre per second + ConversionFactor: 10² kg x m² x s⁻³ + Symbol: mbar·m³/s + CommonCode: F96 + Description: '' + conversion: + factor: 100.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: megapascal litre per second + ConversionFactor: 10³ kg x m² x s⁻³ + Symbol: MPa·l/s + CommonCode: F97 + Description: '' + conversion: + factor: 1000.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: megapascal cubic metre per second + ConversionFactor: 10⁶ kg x m² x s⁻³ + Symbol: MPa·m³/s + CommonCode: F98 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: pascal litre per second + ConversionFactor: 10⁻³ kg x m² x s⁻³ + Symbol: Pa·l/s + CommonCode: F99 + Description: '' + conversion: + factor: 0.001 + base_units: + - G01 +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit + ConversionFactor: 5/9 x K + Symbol: "°F" + CommonCode: FAH + Description: 'Refer ISO 80000-5 (Quantities and units — Part 5: Thermodynamics)' + conversion: + factor: 5.0 + base_units: [] +- Status: '' + LevelAndCategory: '1' + Name: farad + ConversionFactor: F + Symbol: F + CommonCode: FAR + Description: '' + conversion: + factor: 1.0 + base_units: + - FAR +- Status: X + LevelAndCategory: '3.9' + Name: field + ConversionFactor: '' + Symbol: '' + CommonCode: FB + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: fibre metre + ConversionFactor: '' + Symbol: '' + CommonCode: FBM + Description: A unit of length defining the number of metres of individual fibre. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: thousand cubic foot + ConversionFactor: '' + Symbol: kft³ + CommonCode: FC + Description: A unit of volume equal to one thousand cubic foot. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: million particle per cubic foot + ConversionFactor: '' + Symbol: '' + CommonCode: FD + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: track foot + ConversionFactor: '' + Symbol: '' + CommonCode: FE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: hundred cubic metre + ConversionFactor: '' + Symbol: '' + CommonCode: FF + Description: A unit of volume equal to one hundred cubic metres. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: transdermal patch + ConversionFactor: '' + Symbol: '' + CommonCode: FG + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: micromole + ConversionFactor: 10⁻⁶ mol + Symbol: µmol + CommonCode: FH + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C34 +- Status: '' + LevelAndCategory: '3.8' + Name: failures in time + ConversionFactor: 2,777 78 × 10⁻¹³ s⁻¹ + Symbol: '' + CommonCode: FIT + Description: A unit of count defining the number of failures that can be expected + over a specified time interval. Failure rates of semiconductor components are + often specified as FIT (failures in time unit) where 1 FIT = 10⁻⁹ /h. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: flake ton + ConversionFactor: '' + Symbol: '' + CommonCode: FL + Description: 'A unit of mass defining the number of tons of a flaked substance (flake: + a small flattish fragment).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: million cubic foot + ConversionFactor: '' + Symbol: Mft³ + CommonCode: FM + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: foot + ConversionFactor: 0,304 8 m + Symbol: ft + CommonCode: FOT + Description: '' + conversion: + factor: 0.3048 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: pound per square foot + ConversionFactor: 4,882 428 kg/m² + Symbol: lb/ft² + CommonCode: FP + Description: '' + conversion: + factor: 4.882428 + base_units: + - '28' +- Status: '' + LevelAndCategory: '2' + Name: foot per minute + ConversionFactor: 5,08 x 10⁻³ m/s + Symbol: ft/min + CommonCode: FR + Description: '' + conversion: + factor: 0.00508 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: foot per second + ConversionFactor: 0,304 8 m/s + Symbol: ft/s + CommonCode: FS + Description: '' + conversion: + factor: 0.3048 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: square foot + ConversionFactor: 9,290 304 x 10⁻² m² + Symbol: ft² + CommonCode: FTK + Description: '' + conversion: + factor: 0.09290304 + base_units: + - MTK +- Status: '' + LevelAndCategory: '2' + Name: cubic foot + ConversionFactor: 2,831 685 x 10⁻² m³ + Symbol: ft³ + CommonCode: FTQ + Description: '' + conversion: + factor: 0.02831685 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: pascal cubic metre per second + ConversionFactor: kg x m² x s⁻³ + Symbol: Pa·m³/s + CommonCode: G01 + Description: '' + conversion: + factor: 1.0 + base_units: + - G01 +- Status: '' + LevelAndCategory: 1M + Name: centimetre per bar + ConversionFactor: 10⁻⁷ kg⁻¹ x m² x s² + Symbol: cm/bar + CommonCode: G04 + Description: '' + conversion: + factor: 1.0e-07 + base_units: + - M53 +- Status: '' + LevelAndCategory: 1M + Name: metre per bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m² x s² + Symbol: m/bar + CommonCode: G05 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M53 +- Status: '' + LevelAndCategory: 1M + Name: millimetre per bar + ConversionFactor: 10⁻⁸ kg⁻¹ x m² x s² + Symbol: mm/bar + CommonCode: G06 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - M53 +- Status: '' + LevelAndCategory: '2' + Name: square inch per second + ConversionFactor: 6,451 6 × 10⁻⁴ m² x s⁻¹ + Symbol: in²/s + CommonCode: G08 + Description: '' + conversion: + factor: 6.4516 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: square metre per second kelvin + ConversionFactor: m² x s⁻¹ x K⁻¹ + Symbol: m²/(s·K) + CommonCode: G09 + Description: '' + conversion: + factor: 1.0 + base_units: + - G09 +- Status: '' + LevelAndCategory: '2' + Name: stokes per kelvin + ConversionFactor: 10⁻⁴ m² x s⁻¹ x K⁻¹ + Symbol: St/K + CommonCode: G10 + Description: '' + conversion: + factor: 0.0001 + base_units: + - G09 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic centimetre bar + ConversionFactor: 10⁻² m⁻² x s² + Symbol: g/(cm³·bar) + CommonCode: G11 + Description: '' + conversion: + factor: 0.01 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic decimetre bar + ConversionFactor: 10⁻⁵ m⁻² x s² + Symbol: g/(dm³·bar) + CommonCode: G12 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: gram per litre bar + ConversionFactor: 10⁻⁵ m⁻² x s² + Symbol: g/(l·bar) + CommonCode: G13 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic metre bar + ConversionFactor: 10⁻⁸ m⁻² x s² + Symbol: g/(m³·bar) + CommonCode: G14 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: gram per millilitre bar + ConversionFactor: 10⁻² m⁻² x s² + Symbol: g/(ml·bar) + CommonCode: G15 + Description: '' + conversion: + factor: 0.01 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic centimetre bar + ConversionFactor: 10¹ m⁻² x s² + Symbol: kg/(cm³·bar) + CommonCode: G16 + Description: '' + conversion: + factor: 10.0 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per litre bar + ConversionFactor: 10⁻² m⁻² x s² + Symbol: kg/(l·bar) + CommonCode: G17 + Description: '' + conversion: + factor: 0.01 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic metre bar + ConversionFactor: 10⁻⁵ m⁻² x s² + Symbol: kg/(m³·bar) + CommonCode: G18 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M73 +- Status: '' + LevelAndCategory: 1M + Name: newton metre per kilogram + ConversionFactor: m² x s⁻² + Symbol: N·m/kg + CommonCode: G19 + Description: '' + conversion: + factor: 1.0 + base_units: + - G19 +- Status: '' + LevelAndCategory: '2' + Name: US gallon per minute + ConversionFactor: 6,309 020 x 10⁻⁵ m³/s + Symbol: gal (US) /min + CommonCode: G2 + Description: '' + conversion: + factor: 6.30902e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pound-force foot per pound + ConversionFactor: 2,989 07 m² x s⁻² + Symbol: lbf·ft/lb + CommonCode: G20 + Description: '' + conversion: + factor: 2.98907 + base_units: + - G19 +- Status: '' + LevelAndCategory: '2' + Name: cup [unit of volume] + ConversionFactor: 2,365 882 x 10⁻⁴ m³ + Symbol: cup (US) + CommonCode: G21 + Description: '' + conversion: + factor: 0.0002365882 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: peck + ConversionFactor: 8,809 768 x 10⁻³ m³ + Symbol: pk (US) + CommonCode: G23 + Description: '' + conversion: + factor: 0.008809768 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: tablespoon (US) + ConversionFactor: 1,478 676 x 10⁻⁵ m³ + Symbol: tablespoon (US) + CommonCode: G24 + Description: '' + conversion: + factor: 1.478676e-05 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: teaspoon (US) + ConversionFactor: 4,928 922 x 10⁻⁶ m³ + Symbol: teaspoon (US) + CommonCode: G25 + Description: '' + conversion: + factor: 4.928922e-06 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: stere + ConversionFactor: m³ + Symbol: st + CommonCode: G26 + Description: '' + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per kelvin + ConversionFactor: 10⁻⁶ m³ x K⁻¹ + Symbol: cm³/K + CommonCode: G27 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - G29 +- Status: '' + LevelAndCategory: 1M + Name: litre per kelvin + ConversionFactor: 10⁻³ m³ x K⁻¹ + Symbol: l/K + CommonCode: G28 + Description: '' + conversion: + factor: 0.001 + base_units: + - G29 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per kelvin + ConversionFactor: m³ x K⁻¹ + Symbol: m³/K + CommonCode: G29 + Description: '' + conversion: + factor: 1.0 + base_units: + - G29 +- Status: '' + LevelAndCategory: '2' + Name: Imperial gallon per minute + ConversionFactor: 7,576 82 x 10⁻⁵ m³/s + Symbol: gal (UK) /min + CommonCode: G3 + Description: '' + conversion: + factor: 7.57682e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1M + Name: millilitre per kelvin + ConversionFactor: 10⁻⁶ m³ x K⁻¹ + Symbol: ml/K + CommonCode: G30 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - G29 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic centimetre + ConversionFactor: 10⁶ kg x m⁻³ + Symbol: kg/cm³ + CommonCode: G31 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - F23 +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per cubic yard + ConversionFactor: 3,707 98 × 10⁻² kg x m⁻³ + Symbol: oz/yd³ + CommonCode: G32 + Description: '' + conversion: + factor: 3.70798 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic centimetre kelvin + ConversionFactor: 10³ kg x m⁻³ x K⁻¹ + Symbol: g/(cm³·K) + CommonCode: G33 + Description: '' + conversion: + factor: 1000.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic decimetre kelvin + ConversionFactor: kg x m⁻³ x K⁻¹ + Symbol: g/(dm³·K) + CommonCode: G34 + Description: '' + conversion: + factor: 1.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: gram per litre kelvin + ConversionFactor: kg x m⁻³ x K⁻¹ + Symbol: g/(l·K) + CommonCode: G35 + Description: '' + conversion: + factor: 1.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: gram per cubic metre kelvin + ConversionFactor: 10⁻³ kg x m⁻³ x K⁻¹ + Symbol: g/(m³·K) + CommonCode: G36 + Description: '' + conversion: + factor: 0.001 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: gram per millilitre kelvin + ConversionFactor: 10³ kg x m⁻³ x K⁻¹ + Symbol: g/(ml·K) + CommonCode: G37 + Description: '' + conversion: + factor: 1000.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic centimetre kelvin + ConversionFactor: 10⁶ kg x m⁻³ x K⁻¹ + Symbol: kg/(cm³·K) + CommonCode: G38 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per litre kelvin + ConversionFactor: 10³ kg x m⁻³ x K⁻¹ + Symbol: kg/(l·K) + CommonCode: G39 + Description: '' + conversion: + factor: 1000.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic metre kelvin + ConversionFactor: kg x m⁻³ x K⁻¹ + Symbol: kg/(m³·K) + CommonCode: G40 + Description: '' + conversion: + factor: 1.0 + base_units: + - G34 + - G35 + - G40 +- Status: '' + LevelAndCategory: 1M + Name: square metre per second bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m³ x s + Symbol: m²/(s·bar) + CommonCode: G41 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M82 +- Status: '' + LevelAndCategory: 1M + Name: microsiemens per centimetre + ConversionFactor: 10⁻⁴ S/m + Symbol: µS/cm + CommonCode: G42 + Description: '' + conversion: + factor: 0.0001 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1M + Name: microsiemens per metre + ConversionFactor: 10⁻⁶ S/m + Symbol: µS/m + CommonCode: G43 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1M + Name: nanosiemens per centimetre + ConversionFactor: 10⁻⁷ S/m + Symbol: nS/cm + CommonCode: G44 + Description: '' + conversion: + factor: 1.0e-07 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1M + Name: nanosiemens per metre + ConversionFactor: 10⁻⁹ S/m + Symbol: nS/m + CommonCode: G45 + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - D10 +- Status: '' + LevelAndCategory: '2' + Name: stokes per bar + ConversionFactor: 10⁻⁹ kg⁻¹ x m³ x s + Symbol: St/bar + CommonCode: G46 + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - M82 +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per day + ConversionFactor: 1,157 41 × 10⁻¹¹ m³ x s⁻¹ + Symbol: cm³/d + CommonCode: G47 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per hour + ConversionFactor: 2,777 78 × 10⁻¹⁰ m³ x s⁻¹ + Symbol: cm³/h + CommonCode: G48 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per minute + ConversionFactor: 1,666 67 × 10⁻⁸ m³ x s⁻¹ + Symbol: cm³/min + CommonCode: G49 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: gallon (US) per hour + ConversionFactor: 1,051 5 × 10⁻⁶ m³ x s⁻¹ + Symbol: gal/h + CommonCode: G50 + Description: '' + conversion: + factor: 1.0515 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per second + ConversionFactor: 10⁻³ m³ x s⁻¹ + Symbol: l/s + CommonCode: G51 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per day + ConversionFactor: 1,157 41 × 10⁻⁵ m³ x s⁻¹ + Symbol: m³/d + CommonCode: G52 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per minute + ConversionFactor: 1,666 67 × 10⁻² m³ x s⁻¹ + Symbol: m³/min + CommonCode: G53 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per day + ConversionFactor: 1,157 41 × 10⁻¹¹ m³ x s⁻¹ + Symbol: ml/d + CommonCode: G54 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per hour + ConversionFactor: 2,777 78 × 10⁻¹⁰ m³ x s⁻¹ + Symbol: ml/h + CommonCode: G55 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic inch per hour + ConversionFactor: 4,551 96 × 10⁻⁹ m³ x s⁻¹ + Symbol: in³/h + CommonCode: G56 + Description: '' + conversion: + factor: 4.55196 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic inch per minute + ConversionFactor: 2,731 18 × 10⁻⁷ m³ x s⁻¹ + Symbol: in³/min + CommonCode: G57 + Description: '' + conversion: + factor: 2.73118 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic inch per second + ConversionFactor: 1,638 71 × 10⁻⁵ m³ x s⁻¹ + Symbol: in³/s + CommonCode: G58 + Description: '' + conversion: + factor: 1.63871 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milliampere per litre minute + ConversionFactor: 1,666 67 × 10⁻² m⁻³ x s⁻¹ x A + Symbol: mA/(l·min) + CommonCode: G59 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: volt per bar + ConversionFactor: 10⁻⁵ m³ x s⁻¹ x A⁻¹ + Symbol: V/bar + CommonCode: G60 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - N98 +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per day kelvin + ConversionFactor: 1,157 41 × 10⁻¹¹ m³ x s⁻¹ x K⁻¹ + Symbol: cm³/(d·K) + CommonCode: G61 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per hour kelvin + ConversionFactor: 2,777 78 × 10⁻¹⁰ m³ x s⁻¹ x K⁻¹ + Symbol: cm³/(h·K) + CommonCode: G62 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per minute kelvin + ConversionFactor: 1,666 67 × 10⁻⁸ m³ x s⁻¹ x K⁻¹ + Symbol: cm³/(min·K) + CommonCode: G63 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per second kelvin + ConversionFactor: 10⁻⁶ m³ x s⁻¹ x K⁻¹ + Symbol: cm³/(s·K) + CommonCode: G64 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - G72 +- Status: '' + LevelAndCategory: 1M + Name: litre per day kelvin + ConversionFactor: 1,157 41 × 10⁻⁸ m³ x s⁻¹ x K⁻¹ + Symbol: l/(d·K) + CommonCode: G65 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per hour kelvin + ConversionFactor: 2,777 78 × 10⁻⁷ m³ x s⁻¹ x K⁻¹ + Symbol: l/(h·K) + CommonCode: G66 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per minute kelvin + ConversionFactor: 1,666 67 × 10⁻⁵ m³ x s⁻¹ x K⁻¹ + Symbol: l/(min·K) + CommonCode: G67 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per second kelvin + ConversionFactor: 10⁻³ m³ x s⁻¹ x K⁻¹ + Symbol: l/(s·K) + CommonCode: G68 + Description: '' + conversion: + factor: 0.001 + base_units: + - G72 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per day kelvin + ConversionFactor: 1,157 41 × 10⁻⁵ m³ x s⁻¹ x K⁻¹ + Symbol: m³/(d·K) + CommonCode: G69 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: microfiche sheet + ConversionFactor: '' + Symbol: '' + CommonCode: G7 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per hour kelvin + ConversionFactor: 2,777 78 × 10⁻⁴ m³ x s⁻¹ x K⁻¹ + Symbol: m³/(h·K) + CommonCode: G70 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per minute kelvin + ConversionFactor: 1,666 67 × 10⁻² m³ x s⁻¹ x K⁻¹ + Symbol: m³/(min·K) + CommonCode: G71 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per second kelvin + ConversionFactor: m³ x s⁻¹ x K⁻¹ + Symbol: m³/(s·K) + CommonCode: G72 + Description: '' + conversion: + factor: 1.0 + base_units: + - G72 +- Status: '' + LevelAndCategory: 1M + Name: millilitre per day kelvin + ConversionFactor: 1,157 41 × 10⁻¹¹ m³ x s⁻¹ x K⁻¹ + Symbol: ml/(d·K) + CommonCode: G73 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per hour kelvin + ConversionFactor: 2,777 78 × 10⁻¹⁰ m³ x s⁻¹ x K⁻¹ + Symbol: ml/(h·K) + CommonCode: G74 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per minute kelvin + ConversionFactor: 1,666 67 × 10⁻⁸ m³ x s⁻¹ x K⁻¹ + Symbol: ml/(min·K) + CommonCode: G75 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per second kelvin + ConversionFactor: 10⁻⁶ m³ x s⁻¹ x K⁻¹ + Symbol: ml/(s·K) + CommonCode: G76 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - G72 +- Status: '' + LevelAndCategory: 1M + Name: millimetre to the fourth power + ConversionFactor: 10⁻¹² m⁴ + Symbol: mm⁴ + CommonCode: G77 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - B83 +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per day bar + ConversionFactor: 1,157 41 × 10⁻¹⁶ kg⁻¹ x m⁴ x s + Symbol: cm³/(d·bar) + CommonCode: G78 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per hour bar + ConversionFactor: 2,777 78 × 10⁻¹⁵ kg⁻¹ x m⁴ x s + Symbol: cm³/(h·bar) + CommonCode: G79 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per minute bar + ConversionFactor: 1,666 67 × 10⁻¹³ kg⁻¹ x m⁴ x s + Symbol: cm³/(min·bar) + CommonCode: G80 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per second bar + ConversionFactor: 10⁻¹¹ kg⁻¹ x m⁴ x s + Symbol: cm³/(s·bar) + CommonCode: G81 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - N45 +- Status: '' + LevelAndCategory: 1M + Name: litre per day bar + ConversionFactor: 1,157 41 × 10⁻¹³ kg⁻¹ x m⁴ x s + Symbol: l/(d·bar) + CommonCode: G82 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per hour bar + ConversionFactor: 2,777 78 × 10⁻¹² kg⁻¹ x m⁴ x s + Symbol: l/(h·bar) + CommonCode: G83 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per minute bar + ConversionFactor: 1,666 67 × 10⁻¹⁰ kg⁻¹ x m⁴ x s + Symbol: l/(min·bar) + CommonCode: G84 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per second bar + ConversionFactor: 10⁻⁸ kg⁻¹ x m⁴ x s + Symbol: l/(s·bar) + CommonCode: G85 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - N45 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per day bar + ConversionFactor: 1,157 41 × 10⁻¹⁰ kg⁻¹ x m⁴ x s + Symbol: m³/(d·bar) + CommonCode: G86 + Description: '' + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per hour bar + ConversionFactor: 2,777 78 × 10⁻⁹ kg⁻¹ x m⁴ x s + Symbol: m³/(h·bar) + CommonCode: G87 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per minute bar + ConversionFactor: 1,666 67 × 10⁻⁷ kg⁻¹ x m⁴ x s + Symbol: m³/(min·bar) + CommonCode: G88 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per second bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m⁴ x s + Symbol: m³/(s·bar) + CommonCode: G89 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - N45 +- Status: '' + LevelAndCategory: 1M + Name: millilitre per day bar + ConversionFactor: 1,157 41 x 10⁻¹⁶ x kg⁻¹ x m⁴ x s + Symbol: ml/(d·bar) + CommonCode: G90 + Description: '' + conversion: + factor: 1.15741e-16 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per hour bar + ConversionFactor: 2,777 78 x 10⁻¹⁵ x kg⁻¹ x m⁴ x s + Symbol: ml/(h·bar) + CommonCode: G91 + Description: '' + conversion: + factor: 2.77778e-15 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per minute bar + ConversionFactor: 1,666 67 × 10⁻¹³ x kg⁻¹ x m⁴ x s + Symbol: ml/(min·bar) + CommonCode: G92 + Description: '' + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millilitre per second bar + ConversionFactor: 10⁻¹¹ kg⁻¹ x m⁴ x s + Symbol: ml/(s·bar) + CommonCode: G93 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - N45 +- Status: '' + LevelAndCategory: 1M + Name: cubic centimetre per bar + ConversionFactor: 10⁻¹¹ kg⁻¹ x m⁴ x s² + Symbol: cm³/bar + CommonCode: G94 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - M71 +- Status: '' + LevelAndCategory: 1M + Name: litre per bar + ConversionFactor: 10⁻⁸ kg⁻¹ x m⁴ x s² + Symbol: l/bar + CommonCode: G95 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - M71 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per bar + ConversionFactor: 10⁻⁵ kg⁻¹ x m⁴ x s² + Symbol: m³/bar + CommonCode: G96 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M71 +- Status: '' + LevelAndCategory: 1M + Name: millilitre per bar + ConversionFactor: 10⁻¹¹ kg⁻¹ x m⁴ x s² + Symbol: ml/bar + CommonCode: G97 + Description: '' + conversion: + factor: 1.0e-11 + base_units: + - M71 +- Status: '' + LevelAndCategory: 1M + Name: microhenry per kiloohm + ConversionFactor: 10⁻⁹ s + Symbol: µH/kΩ + CommonCode: G98 + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: microhenry per ohm + ConversionFactor: 10⁻⁶ s + Symbol: µH/Ω + CommonCode: G99 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.5' + Name: gallon (US) per day + ConversionFactor: 4,381 264 x 10⁻⁸ m³/s + Symbol: gal (US)/d + CommonCode: GB + Description: '' + conversion: + factor: 4.381264e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1M + Name: gigabecquerel + ConversionFactor: 10⁹ Bq + Symbol: GBq + CommonCode: GBQ + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: X + LevelAndCategory: '3.7' + Name: gram per 100 gram + ConversionFactor: '' + Symbol: '' + CommonCode: GC + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: gross barrel + ConversionFactor: '' + Symbol: '' + CommonCode: GD + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: gram, dry weight + ConversionFactor: '' + Symbol: '' + CommonCode: GDW + Description: A unit of mass defining the number of grams of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: pound per gallon (US) + ConversionFactor: 1,198 264 x 10² kg/m³ + Symbol: lb/gal (US) + CommonCode: GE + Description: '' + conversion: + factor: 119.8264 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1M + Name: gram per metre (gram per 100 centimetres) + ConversionFactor: 10⁻³ kg/m + Symbol: g/m + CommonCode: GF + Description: '' + conversion: + factor: 0.001 + base_units: + - KL +- Status: '' + LevelAndCategory: '3.1' + Name: gram of fissile isotope + ConversionFactor: '' + Symbol: gi F/S + CommonCode: GFI + Description: 'A unit of mass defining the number of grams of a fissile isotope (fissile + isotope: an isotope whose nucleus is able to be split when irradiated with low + energy neutrons).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: great gross + ConversionFactor: '1728' + Symbol: '' + CommonCode: GGR + Description: A unit of count defining the number of units in multiples of 1728 (12 + x 12 x 12). + conversion: + factor: 1728.0 +- Status: X + LevelAndCategory: '3.8' + Name: half gallon (US) + ConversionFactor: '' + Symbol: '' + CommonCode: GH + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: gill (US) + ConversionFactor: 1,182 941 x 10⁻⁴ m³ + Symbol: gi (US) + CommonCode: GIA + Description: '' + conversion: + factor: 0.0001182941 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.1' + Name: gram, including container + ConversionFactor: '' + Symbol: '' + CommonCode: GIC + Description: A unit of mass defining the number of grams of a product, including + its container. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: gill (UK) + ConversionFactor: 1,420 653 x 10⁻⁴ m³ + Symbol: gi (UK) + CommonCode: GII + Description: '' + conversion: + factor: 0.0001420653 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.1' + Name: gram, including inner packaging + ConversionFactor: '' + Symbol: '' + CommonCode: GIP + Description: A unit of mass defining the number of grams of a product, including + its inner packaging materials. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gram per millilitre + ConversionFactor: 10³ kg/m³ + Symbol: g/ml + CommonCode: GJ + Description: '' + conversion: + factor: 1000.0 + base_units: + - GL + - KMQ +- Status: X + LevelAndCategory: '3.7' + Name: gram per kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: GK + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gram per litre + ConversionFactor: kg/m³ + Symbol: g/l + CommonCode: GL + Description: '' + conversion: + factor: 1.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: dry gallon (US) + ConversionFactor: 4,404 884 x 10⁻³ m³ + Symbol: dry gal (US) + CommonCode: GLD + Description: '' + conversion: + factor: 0.004404884 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: gallon (UK) + ConversionFactor: 4,546 092 x 10⁻³ m³ + Symbol: gal (UK) + CommonCode: GLI + Description: '' + conversion: + factor: 0.004546092 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: gallon (US) + ConversionFactor: 3,785 412 x 10⁻³ m³ + Symbol: gal (US) + CommonCode: GLL + Description: '' + conversion: + factor: 0.003785412 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: gram per square metre + ConversionFactor: 10⁻³ kg/m² + Symbol: g/m² + CommonCode: GM + Description: '' + conversion: + factor: 0.001 + base_units: + - '28' +- Status: X + LevelAndCategory: '3.1' + Name: gross gallon + ConversionFactor: '' + Symbol: '' + CommonCode: GN + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: milligram per square metre + ConversionFactor: 10⁻⁶ kg/m² + Symbol: mg/m² + CommonCode: GO + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - '28' +- Status: '' + LevelAndCategory: 1M + Name: milligram per cubic metre + ConversionFactor: 10⁻⁶ kg/m³ + Symbol: mg/m³ + CommonCode: GP + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1M + Name: microgram per cubic metre + ConversionFactor: 10⁻⁹ kg/m³ + Symbol: µg/m³ + CommonCode: GQ + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1S + Name: gram + ConversionFactor: 10⁻³ kg + Symbol: g + CommonCode: GRM + Description: '' + conversion: + factor: 0.001 + base_units: + - KGM +- Status: '' + LevelAndCategory: '2' + Name: grain + ConversionFactor: 64,798 91 x 10⁻⁶ kg + Symbol: gr + CommonCode: GRN + Description: '' + conversion: + factor: 6.479891e-05 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.7' + Name: gross + ConversionFactor: '144' + Symbol: gr + CommonCode: GRO + Description: A unit of count defining the number of units in multiples of 144 (12 + x 12). + conversion: + factor: 144.0 +- Status: D + LevelAndCategory: '3.4' + Name: gross register ton + ConversionFactor: '' + Symbol: '' + CommonCode: GRT + Description: A unit of mass equal to the total cubic footage before deductions, + where 1 register ton is equal to 100 cubic feet. Refer International Convention + on tonnage measurement of ships. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: 3.1,3.4 + Name: gross ton + ConversionFactor: '' + Symbol: '' + CommonCode: GT + Description: 'A unit of mass equal to 2240 pounds. Refer International Convention + on Tonnage measurement of Ships.,Synonym: ton (UK) or long ton (US) (common code + LTN)' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gigajoule + ConversionFactor: 10⁹ J + Symbol: GJ + CommonCode: GV + Description: '' + conversion: + factor: 1000000000.0 + base_units: [] +- Status: X + LevelAndCategory: '3.5' + Name: gallon per thousand cubic foot + ConversionFactor: '' + Symbol: '' + CommonCode: GW + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: gigawatt hour + ConversionFactor: 3,6 x 10¹² J + Symbol: GW·h + CommonCode: GWH + Description: '' + conversion: + factor: 3600000000000.0 + base_units: + - JOU +- Status: X + LevelAndCategory: '3.1' + Name: gross yard + ConversionFactor: '' + Symbol: '' + CommonCode: GY + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: gage system + ConversionFactor: '' + Symbol: '' + CommonCode: GZ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: henry per kiloohm + ConversionFactor: 10⁻³ s + Symbol: H/kΩ + CommonCode: H03 + Description: '' + conversion: + factor: 0.001 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: henry per ohm + ConversionFactor: s + Symbol: H/Ω + CommonCode: H04 + Description: '' + conversion: + factor: 1.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: millihenry per kiloohm + ConversionFactor: 10⁻⁶ s + Symbol: mH/kΩ + CommonCode: H05 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: millihenry per ohm + ConversionFactor: 10⁻³ s + Symbol: mH/Ω + CommonCode: H06 + Description: '' + conversion: + factor: 0.001 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: pascal second per bar + ConversionFactor: 10⁻⁵ s + Symbol: Pa·s/bar + CommonCode: H07 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: microbecquerel + ConversionFactor: 10⁻⁶ Bq + Symbol: µBq + CommonCode: H08 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: reciprocal year + ConversionFactor: 3,168 81 x 10⁻⁸ s⁻¹ + Symbol: 1/y + CommonCode: H09 + Description: '' + conversion: + factor: 3.16881e-08 + base_units: + - C97 +- Status: X + LevelAndCategory: '3.9' + Name: half page – electronic + ConversionFactor: '' + Symbol: '' + CommonCode: H1 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: reciprocal hour + ConversionFactor: 2,777 78 × 10⁻⁴ s⁻¹ + Symbol: 1/h + CommonCode: H10 + Description: '' + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: reciprocal month + ConversionFactor: 3,802 57 × 10⁻⁷ s⁻¹ + Symbol: 1/mo + CommonCode: H11 + Description: '' + conversion: + factor: 3.80257 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: degree Celsius per hour + ConversionFactor: 2,777 78 x 10⁻⁴ s⁻¹ K + Symbol: "°C/h" + CommonCode: H12 + Description: '' + conversion: + factor: 0.000277778 + base_units: + - H14 +- Status: '' + LevelAndCategory: 1M + Name: degree Celsius per minute + ConversionFactor: 1,666 67 x 10⁻² s⁻¹ K + Symbol: "°C/min" + CommonCode: H13 + Description: '' + conversion: + factor: 0.0166667 + base_units: + - H14 +- Status: '' + LevelAndCategory: 1M + Name: degree Celsius per second + ConversionFactor: s⁻¹ K + Symbol: "°C/s" + CommonCode: H14 + Description: '' + conversion: + factor: 1.0 + base_units: + - H14 +- Status: '' + LevelAndCategory: 1M + Name: square centimetre per gram + ConversionFactor: 10⁻¹ kg⁻¹ x m² + Symbol: cm²/g + CommonCode: H15 + Description: '' + conversion: + factor: 0.1 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: square decametre + ConversionFactor: 10² m² + Symbol: dam² + CommonCode: H16 + Description: 'Synonym: are' + conversion: + factor: 100.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: 1S + Name: square hectometre + ConversionFactor: 10⁴ m² + Symbol: hm² + CommonCode: H18 + Description: Synonym: hectare + conversion: + factor: 10000.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: 1S + Name: cubic hectometre + ConversionFactor: 10⁶ m³ + Symbol: hm³ + CommonCode: H19 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.8' + Name: half litre + ConversionFactor: '' + Symbol: '' + CommonCode: H2 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: cubic kilometre + ConversionFactor: 10⁹ m³ + Symbol: km³ + CommonCode: H20 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.2' + Name: blank + ConversionFactor: '' + Symbol: '' + CommonCode: H21 + Description: A unit of count defining the number of blanks. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: volt square inch per pound-force + ConversionFactor: 1,450 377 439 8 × 10⁻⁴ m³ x s⁻¹ x A⁻¹ + Symbol: V/(lbf/in²) + CommonCode: H22 + Description: '' + conversion: + factor: 1.4503774398 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: volt per inch + ConversionFactor: 3,937 007 874 × 10¹ m x kg x s⁻³ x A⁻¹ + Symbol: V/in + CommonCode: H23 + Description: '' + conversion: + factor: 3.937007874 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: volt per microsecond + ConversionFactor: 10⁶ V/s + Symbol: V/µs + CommonCode: H24 + Description: '' + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.7' + Name: percent per kelvin + ConversionFactor: 10⁻² K⁻¹ + Symbol: "%/K" + CommonCode: H25 + Description: A unit of proportion, equal to 0.01, in relation to the SI base unit + Kelvin. + conversion: + factor: 0.01 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: 1M + Name: ohm per metre + ConversionFactor: Ω/m + Symbol: Ω/m + CommonCode: H26 + Description: '' + conversion: + factor: 1.0 + base_units: + - H26 +- Status: '' + LevelAndCategory: '2' + Name: degree per metre + ConversionFactor: 1,745 329 x 10⁻² rad/m + Symbol: "°/m" + CommonCode: H27 + Description: '' + conversion: + factor: 0.01745329 + base_units: + - C84 +- Status: '' + LevelAndCategory: 1S + Name: microfarad per kilometre + ConversionFactor: 10⁻⁹ F/m + Symbol: µF/km + CommonCode: H28 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: microgram per litre + ConversionFactor: 10⁻⁶ m⁻³ x kg + Symbol: µg/l + CommonCode: H29 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: square micrometre (square micron) + ConversionFactor: 10⁻¹² m² + Symbol: µm² + CommonCode: H30 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - MTK +- Status: '' + LevelAndCategory: '1.0' + Name: ampere per kilogram + ConversionFactor: A x kg⁻¹ + Symbol: A/kg + CommonCode: H31 + Description: '' + conversion: + factor: 1.0 + base_units: + - H31 +- Status: '' + LevelAndCategory: '1.0' + Name: ampere squared second + ConversionFactor: A² x s + Symbol: A²·s + CommonCode: H32 + Description: '' + conversion: + factor: 1.0 + base_units: + - H32 +- Status: '' + LevelAndCategory: 1S + Name: farad per kilometre + ConversionFactor: 10⁻³ F/m + Symbol: F/km + CommonCode: H33 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: hertz metre + ConversionFactor: Hz x m + Symbol: Hz·m + CommonCode: H34 + Description: '' + conversion: + factor: 1.0 + base_units: + - H34 +- Status: '' + LevelAndCategory: '1.0' + Name: kelvin metre per watt + ConversionFactor: K x m⁻¹ x kg⁻¹ x s³ + Symbol: K·m/W + CommonCode: H35 + Description: '' + conversion: + factor: 1.0 + base_units: + - H35 +- Status: '' + LevelAndCategory: 1M + Name: megaohm per kilometre + ConversionFactor: 10³ Ω/m + Symbol: MΩ/km + CommonCode: H36 + Description: '' + conversion: + factor: 1000.0 + base_units: + - H26 +- Status: '' + LevelAndCategory: 1M + Name: megaohm per metre + ConversionFactor: 10⁶ Ω/m + Symbol: MΩ/m + CommonCode: H37 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - H26 +- Status: '' + LevelAndCategory: 1S + Name: megaampere + ConversionFactor: 10⁶ A + Symbol: MA + CommonCode: H38 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - AMP +- Status: '' + LevelAndCategory: '2' + Name: megahertz kilometre + ConversionFactor: 10⁹ Hz x m + Symbol: MHz·km + CommonCode: H39 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - H34 +- Status: '' + LevelAndCategory: '1.0' + Name: newton per ampere + ConversionFactor: kg x m x s⁻² x A⁻¹ + Symbol: N/A + CommonCode: H40 + Description: '' + conversion: + factor: 1.0 + base_units: + - H40 +- Status: '' + LevelAndCategory: '2.0' + Name: newton metre watt to the power minus 0,5 + ConversionFactor: kg x m² x s⁻² x W⁻⁰‧⁵ + Symbol: N·m·W⁻⁰‧⁵ + CommonCode: H41 + Description: '' + conversion: + factor: 1.0 + base_units: + - H41 +- Status: '' + LevelAndCategory: 1M + Name: pascal per metre + ConversionFactor: m⁻² kg x s⁻² + Symbol: Pa/m + CommonCode: H42 + Description: '' + conversion: + factor: 1.0 + base_units: + - H42 +- Status: '' + LevelAndCategory: 1S + Name: siemens per centimetre + ConversionFactor: 10² S/m + Symbol: S/cm + CommonCode: H43 + Description: '' + conversion: + factor: 100.0 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1S + Name: teraohm + ConversionFactor: 10¹² Ω + Symbol: TΩ + CommonCode: H44 + Description: '' + conversion: + factor: 1000000000000.0 + base_units: + - OHM +- Status: '' + LevelAndCategory: '1.0' + Name: volt second per metre + ConversionFactor: m x kg x s⁻² x A⁻¹ + Symbol: V·s/m + CommonCode: H45 + Description: '' + conversion: + factor: 1.0 + base_units: + - H45 +- Status: '' + LevelAndCategory: 1S + Name: volt per second + ConversionFactor: m² x kg x s⁻⁴ x A⁻¹ + Symbol: V/s + CommonCode: H46 + Description: '' + conversion: + factor: 1.0 + base_units: + - H46 +- Status: '' + LevelAndCategory: '1.0' + Name: watt per cubic metre + ConversionFactor: m⁻¹ x kg x s⁻³ + Symbol: W/m³ + CommonCode: H47 + Description: '' + conversion: + factor: 1.0 + base_units: + - H47 +- Status: '' + LevelAndCategory: 1S + Name: attofarad + ConversionFactor: 10⁻¹⁸ m⁻² x kg⁻¹ x s⁴ x A² + Symbol: aF + CommonCode: H48 + Description: '' + conversion: + factor: 1.0e-18 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: centimetre per hour + ConversionFactor: 0,277 777 778 × 10⁻⁶ m x s⁻¹ + Symbol: cm/h + CommonCode: H49 + Description: '' + conversion: + factor: 0.277777778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: reciprocal cubic centimetre + ConversionFactor: 10⁶ m⁻³ + Symbol: cm⁻³ + CommonCode: H50 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - C86 +- Status: '' + LevelAndCategory: '1.0' + Name: decibel per kilometre + ConversionFactor: 10⁻⁴ B/m + Symbol: dB/km + CommonCode: H51 + Description: '' + conversion: + factor: 0.0001 + base_units: + - P43 +- Status: '' + LevelAndCategory: '1.0' + Name: decibel per metre + ConversionFactor: 10⁻¹ B/m + Symbol: dB/m + CommonCode: H52 + Description: '' + conversion: + factor: 0.1 + base_units: + - P43 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per bar + ConversionFactor: 10⁻⁵ m x s² + Symbol: kg/bar + CommonCode: H53 + Description: '' + conversion: + factor: 1.0e-05 + base_units: + - M74 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic decimetre kelvin + ConversionFactor: 10³ m⁻³ x kg x K⁻¹ + Symbol: "(kg/dm³)/K" + CommonCode: H54 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic decimetre bar + ConversionFactor: 10⁻² m⁻² x s² + Symbol: "(kg/dm³)/bar" + CommonCode: H55 + Description: '' + conversion: + factor: 0.01 + base_units: + - M73 +- Status: '' + LevelAndCategory: '1.0' + Name: kilogram per square metre second + ConversionFactor: kg m⁻² x s⁻¹ + Symbol: kg/(m²·s) + CommonCode: H56 + Description: '' + conversion: + factor: 1.0 + base_units: + - H56 +- Status: '' + LevelAndCategory: '2.0' + Name: inch per two pi radiant + ConversionFactor: 2,54 x 10⁻² m/(2 x π x rad) + Symbol: in/revolution + CommonCode: H57 + Description: '' + conversion: + factor: 0.0254 + base_units: [] +- Status: '' + LevelAndCategory: '1.0' + Name: metre per volt second + ConversionFactor: m⁻¹ x kg⁻¹ x s² x A + Symbol: m/(V·s) + CommonCode: H58 + Description: '' + conversion: + factor: 1.0 + base_units: + - H58 +- Status: '' + LevelAndCategory: '1.0' + Name: square metre per newton + ConversionFactor: m x kg⁻¹ x s² + Symbol: m²/N + CommonCode: H59 + Description: '' + conversion: + factor: 1.0 + base_units: + - H59 +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per cubic metre + ConversionFactor: '1.0' + Symbol: m³/m³ + CommonCode: H60 + Description: '' + conversion: + factor: 1.0 + base_units: + - E98 + - F02 + - H60 + - L52 + - M91 +- Status: '' + LevelAndCategory: 1S + Name: millisiemens per centimetre + ConversionFactor: 10⁻¹ S/m + Symbol: mS/cm + CommonCode: H61 + Description: '' + conversion: + factor: 0.1 + base_units: + - D10 +- Status: '' + LevelAndCategory: 1M + Name: millivolt per minute + ConversionFactor: 1,666 666 667 × 10⁻⁵ m² x kg x s⁻⁴ x A⁻¹ + Symbol: mV/min + CommonCode: H62 + Description: '' + conversion: + factor: 1.666666667 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: milligram per square centimetre + ConversionFactor: 10⁻² m⁻² x kg + Symbol: mg/cm² + CommonCode: H63 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: milligram per gram + ConversionFactor: 10⁻³ 1 + Symbol: mg/g + CommonCode: H64 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: millilitre per cubic metre + ConversionFactor: 10⁻⁶ 1 + Symbol: ml/m³ + CommonCode: H65 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: millimetre per year + ConversionFactor: 3,15576 × 10⁴ m x s⁻¹ + Symbol: mm/y + CommonCode: H66 + Description: '' + conversion: + factor: 3.15576 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: millimetre per hour + ConversionFactor: 0,277 777 778 × 10⁻⁷ m x s⁻¹ + Symbol: mm/h + CommonCode: H67 + Description: '' + conversion: + factor: 0.277777778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millimole per gram + ConversionFactor: mol x kg⁻¹ + Symbol: mmol/g + CommonCode: H68 + Description: '' + conversion: + factor: 1.0 + base_units: + - H68 +- Status: '' + LevelAndCategory: 1M + Name: picopascal per kilometre + ConversionFactor: 10⁻¹⁵ m⁻² x kg x s⁻² + Symbol: pPa/km + CommonCode: H69 + Description: '' + conversion: + factor: 1.0e-15 + base_units: [] +- Status: '' + LevelAndCategory: '1.0' + Name: picosecond + ConversionFactor: 10⁻¹² s + Symbol: ps + CommonCode: H70 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.7' + Name: percent per month + ConversionFactor: '' + Symbol: "%/mo" + CommonCode: H71 + Description: A unit of proportion, equal to 0.01, in relation to a month. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per hectobar + ConversionFactor: '' + Symbol: "%/hbar" + CommonCode: H72 + Description: A unit of proportion, equal to 0.01, in relation to 100-fold of the + unit bar. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per decakelvin + ConversionFactor: 10⁻³ K⁻¹ + Symbol: "%/daK" + CommonCode: H73 + Description: A unit of proportion, equal to 0.01, in relation to 10-fold of the + SI base unit Kelvin. + conversion: + factor: 0.001 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: 1M + Name: watt per metre + ConversionFactor: W m⁻¹ + Symbol: W/m + CommonCode: H74 + Description: '' + conversion: + factor: 1.0 + base_units: + - H74 +- Status: '' + LevelAndCategory: 1M + Name: decapascal + ConversionFactor: 10¹ Pa + Symbol: daPa + CommonCode: H75 + Description: '' + conversion: + factor: 10.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1M + Name: gram per millimetre + ConversionFactor: 10¹ kg x m⁻¹ + Symbol: g/mm + CommonCode: H76 + Description: '' + conversion: + factor: 10.0 + base_units: [] +- Status: '' + LevelAndCategory: '3' + Name: module width + ConversionFactor: '' + Symbol: MW + CommonCode: H77 + Description: A unit of measure used to describe the breadth of electronic assemblies + as an installation standard or mounting dimension. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: conventional centimetre of water + ConversionFactor: 9,806 65 × 10¹ Pa + Symbol: cm H₂O + CommonCode: H78 + Description: '' + conversion: + factor: 9.80665 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: French gauge + ConversionFactor: 0,333 333 333 × 10⁻³ m + Symbol: Fg + CommonCode: H79 + Description: 'A unit of distance used for measuring the diameter of small tubes + such as urological instruments and catheters.,Synonym: French, Charrière, Charrière + gauge' + conversion: + factor: 0.333333333 + base_units: [] +- Status: '' + LevelAndCategory: '3' + Name: rack unit + ConversionFactor: 4,445 × 10⁻² m + Symbol: U or RU + CommonCode: H80 + Description: A unit of measure used to describe the height in rack units of equipment + intended for mounting in a 19-inch rack or a 23-inch rack. One rack unit is 1.75 + inches (44.45 mm) high. + conversion: + factor: 4.445 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: millimetre per minute + ConversionFactor: 1,666 666 667 × 10⁻⁵ m x s⁻¹ + Symbol: mm/min + CommonCode: H81 + Description: '' + conversion: + factor: 1.666666667 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: big point + ConversionFactor: 0,352 777 8 × 10⁻³ m + Symbol: bp + CommonCode: H82 + Description: 'A unit of length defining the number of big points (big point: Adobe + software(US) defines the big point to be exactly 1/72 inch (0.013 888 9 inch or + 0.352 777 8 millimeters))' + conversion: + factor: 0.3527778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: litre per kilogram + ConversionFactor: 10⁻³ m³ x kg⁻¹ + Symbol: l/kg + CommonCode: H83 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram millimetre + ConversionFactor: 10⁻⁶ kg x m + Symbol: g·mm + CommonCode: H84 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - M94 +- Status: '' + LevelAndCategory: 1M + Name: reciprocal week + ConversionFactor: 1,647 989 452 868 × 10⁻⁶ s⁻¹ + Symbol: 1/wk + CommonCode: H85 + Description: '' + conversion: + factor: 1.647989452868 + base_units: [] +- Status: '' + LevelAndCategory: '3.8' + Name: piece + ConversionFactor: '' + Symbol: '' + CommonCode: H87 + Description: 'A unit of count defining the number of pieces (piece: a single item, + article or exemplar).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megaohm kilometre + ConversionFactor: 10⁹ Ω x m + Symbol: MΩ·km + CommonCode: H88 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - C61 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per ohm + ConversionFactor: 10⁻² Ω⁻¹ + Symbol: "%/Ω" + CommonCode: H89 + Description: A unit of proportion, equal to 0.01, in relation to the SI derived + unit ohm. + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '3.7' + Name: percent per degree + ConversionFactor: 0,572 957 8 rad⁻¹ + Symbol: "%/°" + CommonCode: H90 + Description: A unit of proportion, equal to 0.01, in relation to an angle of one + degree. + conversion: + factor: 0.5729578 + base_units: [] +- Status: '' + LevelAndCategory: '3.7' + Name: percent per ten thousand + ConversionFactor: 10⁻⁶ + Symbol: "%/10000" + CommonCode: H91 + Description: A unit of proportion, equal to 0.01, in relation to multiples of ten + thousand. + conversion: + factor: 1.0e-06 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per one hundred thousand + ConversionFactor: 10⁻⁷ + Symbol: "%/100000" + CommonCode: H92 + Description: A unit of proportion, equal to 0.01, in relation to multiples of one + hundred thousand. + conversion: + factor: 1.0e-07 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per hundred + ConversionFactor: 10⁻⁴ + Symbol: "%/100" + CommonCode: H93 + Description: A unit of proportion, equal to 0.01, in relation to multiples of one + hundred. + conversion: + factor: 0.0001 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per thousand + ConversionFactor: 10⁻⁵ + Symbol: "%/1000" + CommonCode: H94 + Description: A unit of proportion, equal to 0.01, in relation to multiples of one + thousand. + conversion: + factor: 1.0e-05 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per volt + ConversionFactor: 10⁻² V⁻¹ + Symbol: "%/V" + CommonCode: H95 + Description: A unit of proportion, equal to 0.01, in relation to the SI derived + unit volt. + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '3.7' + Name: percent per bar + ConversionFactor: 10⁻⁷ Pa⁻¹ + Symbol: "%/bar" + CommonCode: H96 + Description: A unit of proportion, equal to 0.01, in relation to an atmospheric + pressure of one bar. + conversion: + factor: 1.0e-07 + base_units: + - C96 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per inch + ConversionFactor: 0,393 700 8 m⁻¹ + Symbol: "%/in" + CommonCode: H98 + Description: A unit of proportion, equal to 0.01, in relation to an inch. + conversion: + factor: 0.3937008 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per metre + ConversionFactor: 10⁻² m⁻¹ + Symbol: "%/m" + CommonCode: H99 + Description: A unit of proportion, equal to 0.01, in relation to a metre. + conversion: + factor: 0.01 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.9' + Name: hank + ConversionFactor: '' + Symbol: '' + CommonCode: HA + Description: A unit of length, typically for yarn. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2.0' + Name: hectare + ConversionFactor: 10⁴ m² + Symbol: ha + CommonCode: HAR + Description: 'Synonym: square hectometre' + conversion: + factor: 10000.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: 1M + Name: hectobar + ConversionFactor: 10⁷ Pa + Symbol: hbar + CommonCode: HBA + Description: '' + conversion: + factor: 10000000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.2' + Name: hundred boxes + ConversionFactor: '' + Symbol: '' + CommonCode: HBX + Description: A unit of count defining the number of boxes in multiples of one hundred + box units. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: hundred count + ConversionFactor: '' + Symbol: '' + CommonCode: HC + Description: A unit of count defining the number of units counted in multiples of + 100. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: half dozen + ConversionFactor: '6' + Symbol: '' + CommonCode: HD + Description: '' + conversion: + factor: 6.0 +- Status: '' + LevelAndCategory: '3.1' + Name: hundred kilogram, dry weight + ConversionFactor: '' + Symbol: '' + CommonCode: HDW + Description: A unit of mass defining the number of hundred kilograms of a product, + disregarding the water content of the product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: hundredth of a carat + ConversionFactor: '' + Symbol: '' + CommonCode: HE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: head + ConversionFactor: '' + Symbol: '' + CommonCode: HEA + Description: 'A unit of count defining the number of heads (head: a person or animal + considered as one of a number).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: hundred foot + ConversionFactor: '' + Symbol: '' + CommonCode: HF + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: hectogram + ConversionFactor: 10⁻¹ kg + Symbol: hg + CommonCode: HGM + Description: '' + conversion: + factor: 0.1 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.8' + Name: hundred cubic foot + ConversionFactor: '' + Symbol: '' + CommonCode: HH + Description: A unit of volume equal to one hundred cubic foot. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: hundred sheet + ConversionFactor: '' + Symbol: '' + CommonCode: HI + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: hundred international unit + ConversionFactor: '' + Symbol: '' + CommonCode: HIU + Description: A unit of count defining the number of international units in multiples + of 100. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: metric horse power + ConversionFactor: 735,498 75 W + Symbol: metric hp + CommonCode: HJ + Description: '' + conversion: + factor: 735.49875 + base_units: + - D46 + - P14 + - WTT +- Status: X + LevelAndCategory: '3.8' + Name: hundred kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: HK + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: hundred kilogram, net mass + ConversionFactor: '' + Symbol: '' + CommonCode: HKM + Description: A unit of mass defining the number of hundred kilograms of a product, + after deductions. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: hundred foot (linear) + ConversionFactor: '' + Symbol: '' + CommonCode: HL + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: hectolitre + ConversionFactor: 10⁻¹ m³ + Symbol: hl + CommonCode: HLT + Description: '' + conversion: + factor: 0.1 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: mile per hour (statute mile) + ConversionFactor: 0,447 04 m/s + Symbol: mile/h + CommonCode: HM + Description: '' + conversion: + factor: 0.44704 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '3.8' + Name: million cubic metre + ConversionFactor: '' + Symbol: Mm³ + CommonCode: HMQ + Description: A unit of volume equal to one million cubic metres. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: hectometre + ConversionFactor: 10² m + Symbol: hm + CommonCode: HMT + Description: '' + conversion: + factor: 100.0 + base_units: + - MTR +- Status: D + LevelAndCategory: '2' + Name: conventional millimetre of mercury + ConversionFactor: 133,322 4 Pa + Symbol: mm Hg + CommonCode: HN + Description: '' + conversion: + factor: 133.3224 + base_units: + - C55 + - PAL +- Status: X + LevelAndCategory: '3.8' + Name: hundred troy ounce + ConversionFactor: '' + Symbol: '' + CommonCode: HO + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: conventional millimetre of water + ConversionFactor: 9,806 65 Pa + Symbol: mm H₂O + CommonCode: HP + Description: '' + conversion: + factor: 9.80665 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.1' + Name: hectolitre of pure alcohol + ConversionFactor: '' + Symbol: '' + CommonCode: HPA + Description: A unit of volume equal to one hundred litres of pure alcohol. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: hundred square foot + ConversionFactor: '' + Symbol: '' + CommonCode: HS + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: half hour + ConversionFactor: '' + Symbol: '' + CommonCode: HT + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: hertz + ConversionFactor: Hz + Symbol: Hz + CommonCode: HTZ + Description: '' + conversion: + factor: 1.0 + base_units: + - HTZ +- Status: '' + LevelAndCategory: '1' + Name: hour + ConversionFactor: 3 600 s + Symbol: h + CommonCode: HUR + Description: '' + conversion: + factor: 3600.0 + base_units: + - H04 + - SEC +- Status: X + LevelAndCategory: '3.8' + Name: hundred yard + ConversionFactor: '' + Symbol: '' + CommonCode: HY + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: inch pound (pound inch) + ConversionFactor: 1,152 12 x 10⁻² kg x m + Symbol: in·lb + CommonCode: IA + Description: '' + conversion: + factor: 0.0115212 + base_units: + - M94 +- Status: X + LevelAndCategory: '3.9' + Name: count per inch + ConversionFactor: '' + Symbol: '' + CommonCode: IC + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: person + ConversionFactor: '' + Symbol: '' + CommonCode: IE + Description: A unit of count defining the number of persons. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: inches of water + ConversionFactor: '' + Symbol: '' + CommonCode: IF + Description: Use inch of water (common code F78) + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: column inch + ConversionFactor: '' + Symbol: '' + CommonCode: II + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: inch per minute + ConversionFactor: '' + Symbol: '' + CommonCode: IL + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: impression + ConversionFactor: '' + Symbol: '' + CommonCode: IM + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: inch + ConversionFactor: 25,4 x 10⁻³ m + Symbol: in + CommonCode: INH + Description: '' + conversion: + factor: 0.0254 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: square inch + ConversionFactor: 6,451 6 x 10⁻⁴ m² + Symbol: in² + CommonCode: INK + Description: '' + conversion: + factor: 0.00064516 + base_units: + - MTK +- Status: '' + LevelAndCategory: '2' + Name: cubic inch + ConversionFactor: 16,387 064 x 10⁻⁶ m³ + Symbol: in³ + CommonCode: INQ + Description: 'Synonym: inch cubed' + conversion: + factor: 1.6387064e-05 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.9' + Name: insurance policy + ConversionFactor: '' + Symbol: '' + CommonCode: IP + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: international sugar degree + ConversionFactor: '' + Symbol: '' + CommonCode: ISD + Description: A unit of measure defining the sugar content of a solution, expressed + in degrees. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: count per centimetre + ConversionFactor: '' + Symbol: '' + CommonCode: IT + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: inch per second + ConversionFactor: 0,025 4 m/s + Symbol: in/s + CommonCode: IU + Description: '' + conversion: + factor: 0.0254 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '3.7' + Name: international unit per gram + ConversionFactor: '' + Symbol: '' + CommonCode: IUG + Description: A unit of count defining the number of international units per gram. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: inch per second squared + ConversionFactor: 0,025 4 m/s² + Symbol: in/s² + CommonCode: IV + Description: '' + conversion: + factor: 0.0254 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per millimetre + ConversionFactor: 10 m⁻¹ + Symbol: "%/mm" + CommonCode: J10 + Description: A unit of proportion, equal to 0.01, in relation to a millimetre. + conversion: + factor: 10.0 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.7' + Name: per mille per psi + ConversionFactor: 1,450 377 x 10⁻⁷ Pa⁻¹ + Symbol: "‰/psi" + CommonCode: J12 + Description: A unit of pressure equal to one thousandth of a psi (pound-force per + square inch). + conversion: + factor: 1.450377e-07 + base_units: + - C96 +- Status: '' + LevelAndCategory: '3.5' + Name: degree API + ConversionFactor: '' + Symbol: "°API" + CommonCode: J13 + Description: 'A unit of relative density as a measure of how heavy or light a petroleum + liquid is compared to water (API: American Petroleum Institute).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Baume (origin scale) + ConversionFactor: '' + Symbol: "°Bé" + CommonCode: J14 + Description: A traditional unit of relative density for liquids. Named after Antoine + Baumé. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Baume (US heavy) + ConversionFactor: '' + Symbol: "°Bé (US heavy)" + CommonCode: J15 + Description: A unit of relative density for liquids heavier than water. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Baume (US light) + ConversionFactor: '' + Symbol: "°Bé (US light)" + CommonCode: J16 + Description: A unit of relative density for liquids lighter than water. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Balling + ConversionFactor: '' + Symbol: "°Balling" + CommonCode: J17 + Description: A unit of density as a measure of sugar content, especially of beer + wort. Named after Karl Balling. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Brix + ConversionFactor: '' + Symbol: "°Bx" + CommonCode: J18 + Description: A unit of proportion used in measuring the dissolved sugar-to-water + mass ratio of a liquid. Named after Adolf Brix. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit hour square foot per British thermal unit (thermochemical) + ConversionFactor: 0,176 228 m² x K/W + Symbol: "°F·h·ft²/Btuth" + CommonCode: J19 + Description: '' + conversion: + factor: 0.176228 + base_units: + - D19 +- Status: '' + LevelAndCategory: '1' + Name: joule per kilogram + ConversionFactor: J/kg + Symbol: J/kg + CommonCode: J2 + Description: '' + conversion: + factor: 1.0 + base_units: + - J2 +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit per kelvin + ConversionFactor: 0,555 555 6 + Symbol: "°F/K" + CommonCode: J20 + Description: '' + conversion: + factor: 0.5555556 +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit per bar + ConversionFactor: 0,555 555 6 x 10⁻⁵ K/Pa + Symbol: "°F/bar" + CommonCode: J21 + Description: '' + conversion: + factor: 5.555556e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit hour square foot per British thermal unit (international + table) + ConversionFactor: 0,176 110 2 m² x K/W + Symbol: "°F·h·ft²/BtuIT" + CommonCode: J22 + Description: '' + conversion: + factor: 0.1761102 + base_units: + - D19 +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit per hour + ConversionFactor: 1,543 210 x 10⁻⁴ K/s + Symbol: "°F/h" + CommonCode: J23 + Description: '' + conversion: + factor: 0.000154321 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit per minute + ConversionFactor: 9,259 259 x 10⁻³ K/s + Symbol: "°F/min" + CommonCode: J24 + Description: '' + conversion: + factor: 0.009259259 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: degree Fahrenheit per second + ConversionFactor: 0,555 555 6 K/s + Symbol: "°F/s" + CommonCode: J25 + Description: '' + conversion: + factor: 0.5555556 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: reciprocal degree Fahrenheit + ConversionFactor: 1,8 1/K + Symbol: 1/°F + CommonCode: J26 + Description: '' + conversion: + factor: 1.81 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: degree Oechsle + ConversionFactor: '' + Symbol: "°Oechsle" + CommonCode: J27 + Description: A unit of density as a measure of sugar content of must, the unfermented + liqueur from which wine is made. Named after Ferdinand Oechsle. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: degree Rankine per hour + ConversionFactor: 1,543 210 x 10⁻⁴ K/s + Symbol: "°R/h" + CommonCode: J28 + Description: '' + conversion: + factor: 0.000154321 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: degree Rankine per minute + ConversionFactor: 9,259 259 x 10⁻³ K/s + Symbol: "°R/min" + CommonCode: J29 + Description: '' + conversion: + factor: 0.009259259 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: degree Rankine per second + ConversionFactor: 0,555 555 6 K/s + Symbol: "°R/s" + CommonCode: J30 + Description: '' + conversion: + factor: 0.5555556 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: degree Twaddell + ConversionFactor: '' + Symbol: "°Tw" + CommonCode: J31 + Description: A unit of density for liquids that are heavier than water. 1 degree + Twaddle represents a difference in specific gravity of 0.005. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: micropoise + ConversionFactor: 10⁻⁶ Pa x s + Symbol: µP + CommonCode: J32 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: 1S + Name: microgram per kilogram + ConversionFactor: 10⁻⁹ + Symbol: µg/kg + CommonCode: J33 + Description: '' + conversion: + factor: 1.0e-09 +- Status: '' + LevelAndCategory: '2' + Name: microgram per cubic metre kelvin + ConversionFactor: 10⁻⁹ (kg/m³)/K + Symbol: "(µg/m³)/K" + CommonCode: J34 + Description: '' + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: microgram per cubic metre bar + ConversionFactor: 10⁻¹⁴ (kg/m³)/Pa + Symbol: "(µg/m³)/bar" + CommonCode: J35 + Description: '' + conversion: + factor: 1.0e-14 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: microlitre per litre + ConversionFactor: 10⁻⁶ + Symbol: µl/l + CommonCode: J36 + Description: '' + conversion: + factor: 1.0e-06 +- Status: '' + LevelAndCategory: '3.6' + Name: baud + ConversionFactor: '' + Symbol: Bd + CommonCode: J38 + Description: A unit of signal transmission speed equal to one signalling event per + second. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (mean) + ConversionFactor: 1,055 87 x 10³ J + Symbol: Btu + CommonCode: J39 + Description: '' + conversion: + factor: 1055.87 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) foot per hour square foot degree + Fahrenheit + ConversionFactor: 1,730 735 W/(m x K) + Symbol: BtuIT·ft/(h·ft²·°F) + CommonCode: J40 + Description: '' + conversion: + factor: 1.730735 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) inch per hour square foot degree + Fahrenheit + ConversionFactor: 0,144 227 9 W/(m x K) + Symbol: BtuIT·in/(h·ft²·°F) + CommonCode: J41 + Description: '' + conversion: + factor: 0.1442279 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) inch per second square foot degree + Fahrenheit + ConversionFactor: 5,192 204 x 10² W/(m x K) + Symbol: BtuIT·in/(s·ft²·°F) + CommonCode: J42 + Description: '' + conversion: + factor: 519.2204 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per pound degree Fahrenheit + ConversionFactor: 4,186 8 x 10³ J/(kg x K) + Symbol: BtuIT/(lb·°F) + CommonCode: J43 + Description: '' + conversion: + factor: 4186.8 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per minute + ConversionFactor: 17,584 266 W + Symbol: BtuIT/min + CommonCode: J44 + Description: '' + conversion: + factor: 17.584266 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per second + ConversionFactor: 1,055 056 x 10³ W + Symbol: BtuIT/s + CommonCode: J45 + Description: '' + conversion: + factor: 1055.056 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) foot per hour square foot degree Fahrenheit + ConversionFactor: 1,729 577 W/(m x K) + Symbol: Btuth·ft/(h·ft²·°F) + CommonCode: J46 + Description: '' + conversion: + factor: 1.729577 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per hour + ConversionFactor: 0,292 875 1 W + Symbol: Btuth/h + CommonCode: J47 + Description: '' + conversion: + factor: 0.2928751 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) inch per hour square foot degree Fahrenheit + ConversionFactor: 0,144 131 4 W/(m x K) + Symbol: Btuth·in/(h·ft²·°F) + CommonCode: J48 + Description: '' + conversion: + factor: 0.1441314 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) inch per second square foot degree Fahrenheit + ConversionFactor: 5,188 732 x 10² W/(m x K) + Symbol: Btuth·in/(s·ft²·°F) + CommonCode: J49 + Description: '' + conversion: + factor: 518.8732 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per pound degree Fahrenheit + ConversionFactor: 4,184 x 10³ J/(kg x K) + Symbol: Btuth/(lb·°F) + CommonCode: J50 + Description: '' + conversion: + factor: 4184.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per minute + ConversionFactor: 17,572 50 W + Symbol: Btuth/min + CommonCode: J51 + Description: '' + conversion: + factor: 17.5725 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per second + ConversionFactor: 1,054 350 x 10³ W + Symbol: Btuth/s + CommonCode: J52 + Description: '' + conversion: + factor: 1054.35 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: coulomb square metre per kilogram + ConversionFactor: C x m²/kg + Symbol: C·m²/kg + CommonCode: J53 + Description: '' + conversion: + factor: 1.0 + base_units: + - J53 +- Status: '' + LevelAndCategory: '3.6' + Name: megabaud + ConversionFactor: 10⁶ Bd + Symbol: MBd + CommonCode: J54 + Description: A unit of signal transmission speed equal to 10⁶ (1000000) signaling + events per second. + conversion: + factor: 1000000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: watt second + ConversionFactor: W x s + Symbol: W·s + CommonCode: J55 + Description: '' + conversion: + factor: 1.0 + base_units: + - J55 +- Status: '' + LevelAndCategory: '2' + Name: bar per bar + ConversionFactor: '1' + Symbol: bar/bar + CommonCode: J56 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: barrel (UK petroleum) + ConversionFactor: 0,159 113 15 m³ + Symbol: bbl (UK liq.) + CommonCode: J57 + Description: '' + conversion: + factor: 0.15911315 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: barrel (UK petroleum) per minute + ConversionFactor: 2,651 886 m³/s + Symbol: bbl (UK liq.)/min + CommonCode: J58 + Description: '' + conversion: + factor: 2.651886 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (UK petroleum) per day + ConversionFactor: 1,841 587 4 x 10⁻⁶ m³/s + Symbol: bbl (UK liq.)/d + CommonCode: J59 + Description: '' + conversion: + factor: 1.8415874e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (UK petroleum) per hour + ConversionFactor: 4,419 810 x 10⁻⁵ m³/s + Symbol: bbl (UK liq.)/h + CommonCode: J60 + Description: '' + conversion: + factor: 4.41981e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (UK petroleum) per second + ConversionFactor: 0,159 113 15 m³/s + Symbol: bbl (UK liq.)/s + CommonCode: J61 + Description: '' + conversion: + factor: 0.15911315 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (US petroleum) per hour + ConversionFactor: 4,416 314 x 10⁻⁵ m³/s + Symbol: bbl (US)/h + CommonCode: J62 + Description: '' + conversion: + factor: 4.416314e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: barrel (US petroleum) per second + ConversionFactor: 0,158 987 3 m³/s + Symbol: bbl (US)/s + CommonCode: J63 + Description: '' + conversion: + factor: 0.1589873 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (UK) per day + ConversionFactor: 4,209 343 x 10⁻⁷ m³/s + Symbol: bu (UK)/d + CommonCode: J64 + Description: '' + conversion: + factor: 4.209343e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (UK) per hour + ConversionFactor: 1,010 242 x 10⁻⁵ m³/s + Symbol: bu (UK)/h + CommonCode: J65 + Description: '' + conversion: + factor: 1.010242e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (UK) per minute + ConversionFactor: 6,061 453 x 10⁻⁴ m³/s + Symbol: bu (UK)/min + CommonCode: J66 + Description: '' + conversion: + factor: 0.0006061453 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (UK) per second + ConversionFactor: 3,636 872 x 10⁻² m³/s + Symbol: bu (UK)/s + CommonCode: J67 + Description: '' + conversion: + factor: 0.03636872 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (US dry) per day + ConversionFactor: 4,078 596 x 10⁻⁷ m³/s + Symbol: bu (US dry)/d + CommonCode: J68 + Description: '' + conversion: + factor: 4.078596e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (US dry) per hour + ConversionFactor: 9,788 631 x 10⁻⁶ m³/s + Symbol: bu (US dry)/h + CommonCode: J69 + Description: '' + conversion: + factor: 9.788631e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (US dry) per minute + ConversionFactor: 5,873 178 x 10⁻⁴ m³/s + Symbol: bu (US dry)/min + CommonCode: J70 + Description: '' + conversion: + factor: 0.0005873178 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: bushel (US dry) per second + ConversionFactor: 3,523 907 x 10⁻² m³/s + Symbol: bu (US dry)/s + CommonCode: J71 + Description: '' + conversion: + factor: 0.03523907 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1S + Name: centinewton metre + ConversionFactor: 10⁻² N x m + Symbol: cN·m + CommonCode: J72 + Description: '' + conversion: + factor: 0.01 + base_units: + - NU +- Status: '' + LevelAndCategory: '2' + Name: centipoise per kelvin + ConversionFactor: 10⁻³ Pa x s/K + Symbol: cP/K + CommonCode: J73 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: centipoise per bar + ConversionFactor: 10⁻⁸ s + Symbol: cP/bar + CommonCode: J74 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '2' + Name: calorie (mean) + ConversionFactor: 4,190 02 J + Symbol: cal + CommonCode: J75 + Description: '' + conversion: + factor: 4.19002 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: calorie (international table) per gram degree Celsius + ConversionFactor: 4,186 8 x 10³ J/(kg x K) + Symbol: calIT/(g·°C) + CommonCode: J76 + Description: '' + conversion: + factor: 4186.8 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: calorie (thermochemical) per centimetre second degree Celsius + ConversionFactor: 4,184 x 10² W/(m x K) + Symbol: calth/(cm·s·°C) + CommonCode: J78 + Description: '' + conversion: + factor: 418.4 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2' + Name: calorie (thermochemical) per gram degree Celsius + ConversionFactor: 4,184 x 10³ J/(kg x K) + Symbol: calth/(g·°C) + CommonCode: J79 + Description: '' + conversion: + factor: 4184.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: calorie (thermochemical) per minute + ConversionFactor: 6,973 333 x 10⁻² W + Symbol: calth/min + CommonCode: J81 + Description: '' + conversion: + factor: 0.06973333 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: calorie (thermochemical) per second + ConversionFactor: 4,184 W + Symbol: calth/s + CommonCode: J82 + Description: '' + conversion: + factor: 4.184 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: clo + ConversionFactor: 0,155 m² x K/W + Symbol: clo + CommonCode: J83 + Description: '' + conversion: + factor: 0.155 + base_units: + - D19 +- Status: '' + LevelAndCategory: '2' + Name: centimetre per second kelvin + ConversionFactor: 10⁻² (m/s)/K + Symbol: "(cm/s)/K" + CommonCode: J84 + Description: '' + conversion: + factor: 0.01 + base_units: + - L12 +- Status: '' + LevelAndCategory: '2' + Name: centimetre per second bar + ConversionFactor: 10⁻⁷ (m/s)/Pa + Symbol: "(cm/s)/bar" + CommonCode: J85 + Description: '' + conversion: + factor: 1.0e-07 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: cubic centimetre per cubic metre + ConversionFactor: 10⁻⁶ + Symbol: cm³/m³ + CommonCode: J87 + Description: '' + conversion: + factor: 1.0e-06 +- Status: D + LevelAndCategory: '2' + Name: centimetre of mercury + ConversionFactor: 1,333 224 x 10³ Pa + Symbol: cm Hg + CommonCode: J89 + Description: '' + conversion: + factor: 1333.224 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per day + ConversionFactor: 1,157 41 x 10⁻⁸ m³/s + Symbol: dm³/d + CommonCode: J90 + Description: '' + conversion: + factor: 1.15741e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per cubic metre + ConversionFactor: 10⁻³ + Symbol: dm³/m³ + CommonCode: J91 + Description: '' + conversion: + factor: 0.001 +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per minute + ConversionFactor: 1,666 67 x 10⁻⁵ m³/s + Symbol: dm³/min + CommonCode: J92 + Description: '' + conversion: + factor: 1.66667e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1S + Name: cubic decimetre per second + ConversionFactor: 10⁻³ m³/s + Symbol: dm³/s + CommonCode: J93 + Description: '' + conversion: + factor: 0.001 + base_units: + - MQS +- Status: D + LevelAndCategory: '2' + Name: dyne centimetre + ConversionFactor: 10⁻⁷ N x m + Symbol: dyn·cm + CommonCode: J94 + Description: '' + conversion: + factor: 1.0e-07 + base_units: + - NU +- Status: '' + LevelAndCategory: '2' + Name: ounce (UK fluid) per day + ConversionFactor: 3,288 549 x 10⁻¹⁰ m³/s + Symbol: fl oz (UK)/d + CommonCode: J95 + Description: '' + conversion: + factor: 3.288549e-10 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (UK fluid) per hour + ConversionFactor: 7,892 517 x 10⁻⁹ m³/s + Symbol: fl oz (UK)/h + CommonCode: J96 + Description: '' + conversion: + factor: 7.892517e-09 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (UK fluid) per minute + ConversionFactor: 4,735 51 x 10⁻⁷ m³/s + Symbol: fl oz (UK)/min + CommonCode: J97 + Description: '' + conversion: + factor: 4.73551e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (UK fluid) per second + ConversionFactor: 2,841 306 x 10⁻⁵ m³/s + Symbol: fl oz (UK)/s + CommonCode: J98 + Description: '' + conversion: + factor: 2.841306e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (US fluid) per day + ConversionFactor: 3,422 862 x 10⁻¹⁰ m³/s + Symbol: fl oz (US)/d + CommonCode: J99 + Description: '' + conversion: + factor: 3.422862e-10 + base_units: + - MQS +- Status: X + LevelAndCategory: '3.4' + Name: jumbo + ConversionFactor: '' + Symbol: '' + CommonCode: JB + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: joule per kelvin + ConversionFactor: J/K + Symbol: J/K + CommonCode: JE + Description: '' + conversion: + factor: 1.0 + base_units: + - JE +- Status: X + LevelAndCategory: '3.3' + Name: jug + ConversionFactor: '' + Symbol: '' + CommonCode: JG + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megajoule per kilogram + ConversionFactor: 10⁶ J/kg + Symbol: MJ/kg + CommonCode: JK + Description: '' + conversion: + factor: 1000000.0 + base_units: + - J2 +- Status: '' + LevelAndCategory: 1M + Name: megajoule per cubic metre + ConversionFactor: 10⁶ J/m³ + Symbol: MJ/m³ + CommonCode: JM + Description: '' + conversion: + factor: 1000000.0 + base_units: + - B8 +- Status: '' + LevelAndCategory: '3.5' + Name: pipeline joint + ConversionFactor: '' + Symbol: '' + CommonCode: JNT + Description: A count of the number of pipeline joints. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: joint + ConversionFactor: '' + Symbol: '' + CommonCode: JO + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: joule + ConversionFactor: J + Symbol: J + CommonCode: JOU + Description: '' + conversion: + factor: 1.0 + base_units: + - JOU +- Status: '' + LevelAndCategory: '3.1' + Name: hundred metre + ConversionFactor: '' + Symbol: '' + CommonCode: JPS + Description: A unit of count defining the number of 100 metre lengths. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: jar + ConversionFactor: '' + Symbol: '' + CommonCode: JR + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: number of jewels + ConversionFactor: '' + Symbol: '' + CommonCode: JWL + Description: 'A unit of count defining the number of jewels (jewel: precious stone).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: kilowatt demand + ConversionFactor: '' + Symbol: '' + CommonCode: K1 + Description: A unit of measure defining the power load measured at predetermined + intervals. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: ounce (US fluid) per hour + ConversionFactor: 8,214 869 x 10⁻⁹ m³/s + Symbol: fl oz (US)/h + CommonCode: K10 + Description: '' + conversion: + factor: 8.214869e-09 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (US fluid) per minute + ConversionFactor: 4,928 922 x 10⁻⁷ m³/s + Symbol: fl oz (US)/min + CommonCode: K11 + Description: '' + conversion: + factor: 4.928922e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: ounce (US fluid) per second + ConversionFactor: 2,957 353 x 10⁻⁵ m³/s + Symbol: fl oz (US)/s + CommonCode: K12 + Description: '' + conversion: + factor: 2.957353e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: foot per degree Fahrenheit + ConversionFactor: 0,548 64 m/K + Symbol: ft/°F + CommonCode: K13 + Description: '' + conversion: + factor: 0.54864 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: foot per hour + ConversionFactor: 8,466 667 x 10⁻⁵m/s + Symbol: ft/h + CommonCode: K14 + Description: '' + conversion: + factor: 8.466667e-05 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: foot pound-force per hour + ConversionFactor: 3,766 161 x 10⁻⁴ W + Symbol: ft·lbf/h + CommonCode: K15 + Description: '' + conversion: + factor: 0.0003766161 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: foot pound-force per minute + ConversionFactor: 2,259 697 x 10⁻² W + Symbol: ft·lbf/min + CommonCode: K16 + Description: '' + conversion: + factor: 0.02259697 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: foot per psi + ConversionFactor: 4,420 750 x 10⁻⁵ m/Pa + Symbol: ft/psi + CommonCode: K17 + Description: '' + conversion: + factor: 4.42075e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: foot per second degree Fahrenheit + ConversionFactor: 0,548 64 (m/s)/K + Symbol: "(ft/s)/°F" + CommonCode: K18 + Description: '' + conversion: + factor: 0.54864 + base_units: + - L12 +- Status: '' + LevelAndCategory: '2' + Name: foot per second psi + ConversionFactor: 4,420 750 x 10⁻⁵ (m/s)/Pa + Symbol: "(ft/s)/psi" + CommonCode: K19 + Description: '' + conversion: + factor: 4.42075e-05 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: kilovolt ampere reactive demand + ConversionFactor: '' + Symbol: '' + CommonCode: K2 + Description: A unit of measure defining the reactive power demand equal to one kilovolt + ampere of reactive power. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: reciprocal cubic foot + ConversionFactor: 35,314 66 m⁻³ + Symbol: 1/ft³ + CommonCode: K20 + Description: '' + conversion: + factor: 35.31466 + base_units: + - C86 +- Status: '' + LevelAndCategory: '2' + Name: cubic foot per degree Fahrenheit + ConversionFactor: 5,097 033 x 10⁻² m³/K + Symbol: ft³/°F + CommonCode: K21 + Description: '' + conversion: + factor: 0.05097033 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic foot per day + ConversionFactor: 3,277 413 x 10⁻⁷ m³/s + Symbol: ft³/d + CommonCode: K22 + Description: '' + conversion: + factor: 3.277413e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic foot per psi + ConversionFactor: 4,107 012 x 10⁻⁶ m³/Pa + Symbol: ft³/psi + CommonCode: K23 + Description: '' + conversion: + factor: 4.107012e-06 + base_units: [] +- Status: D + LevelAndCategory: '2' + Name: foot of water + ConversionFactor: 2,989 067 x 10³ Pa + Symbol: ft H₂O + CommonCode: K24 + Description: '' + conversion: + factor: 2989.067 + base_units: + - C55 + - PAL +- Status: D + LevelAndCategory: '2' + Name: foot of mercury + ConversionFactor: 4,063 666 x 10⁴ Pa + Symbol: ft Hg + CommonCode: K25 + Description: '' + conversion: + factor: 40636.66 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: gallon (UK) per day + ConversionFactor: 5,261 678 x 10⁻⁸ m³/s + Symbol: gal (UK)/d + CommonCode: K26 + Description: '' + conversion: + factor: 5.261678e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gallon (UK) per hour + ConversionFactor: 1,262 803 x 10⁻⁶ m³/s + Symbol: gal (UK)/h + CommonCode: K27 + Description: '' + conversion: + factor: 1.262803e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gallon (UK) per second + ConversionFactor: 4,546 09 x 10⁻³ m³/s + Symbol: gal (UK)/s + CommonCode: K28 + Description: '' + conversion: + factor: 0.00454609 + base_units: + - MQS +- Status: '' + LevelAndCategory: '3.5' + Name: kilovolt ampere reactive hour + ConversionFactor: '' + Symbol: kvar·h + CommonCode: K3 + Description: A unit of measure defining the accumulated reactive energy equal to + one kilovolt ampere of reactive power per hour. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: gallon (US liquid) per second + ConversionFactor: 3,785 412 x 10⁻³ m³/s + Symbol: gal (US liq.)/s + CommonCode: K30 + Description: '' + conversion: + factor: 0.003785412 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gram-force per square centimetre + ConversionFactor: 98,066 5 Pa + Symbol: gf/cm² + CommonCode: K31 + Description: '' + conversion: + factor: 98.0665 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: gill (UK) per day + ConversionFactor: 1,644 274 x 10⁻⁵ m³/s + Symbol: gi (UK)/d + CommonCode: K32 + Description: '' + conversion: + factor: 1.644274e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (UK) per hour + ConversionFactor: 3,946 258 x 10⁻⁸ m³/s + Symbol: gi (UK)/h + CommonCode: K33 + Description: '' + conversion: + factor: 3.946258e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (UK) per minute + ConversionFactor: 0,023 677 55 m³/s + Symbol: gi (UK)/min + CommonCode: K34 + Description: '' + conversion: + factor: 0.02367755 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (UK) per second + ConversionFactor: 1,420 653 x 10⁻⁴ m³/s + Symbol: gi (UK)/s + CommonCode: K35 + Description: '' + conversion: + factor: 0.0001420653 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (US) per day + ConversionFactor: 1,369 145 x 10⁻⁹ m³/s + Symbol: gi (US)/d + CommonCode: K36 + Description: '' + conversion: + factor: 1.369145e-09 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (US) per hour + ConversionFactor: 3,285 947 x 10⁻⁸ m³/s + Symbol: gi (US)/h + CommonCode: K37 + Description: '' + conversion: + factor: 3.285947e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (US) per minute + ConversionFactor: 1,971 568 x 10⁻⁶ m³/s + Symbol: gi (US)/min + CommonCode: K38 + Description: '' + conversion: + factor: 1.971568e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: gill (US) per second + ConversionFactor: 1,182 941 x 10⁻⁴ m³/s + Symbol: gi (US)/s + CommonCode: K39 + Description: '' + conversion: + factor: 0.0001182941 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: standard acceleration of free fall + ConversionFactor: 9,806 65 m/s² + Symbol: gn + CommonCode: K40 + Description: '' + conversion: + factor: 9.80665 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '2' + Name: grain per gallon (US) + ConversionFactor: 1,711 806 x 10⁻² kg/m³ + Symbol: gr/gal (US) + CommonCode: K41 + Description: '' + conversion: + factor: 0.01711806 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: horsepower (boiler) + ConversionFactor: 9,809 50 x 10³ W + Symbol: boiler hp + CommonCode: K42 + Description: '' + conversion: + factor: 9809.5 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: horsepower (electric) + ConversionFactor: 746 W + Symbol: electric hp + CommonCode: K43 + Description: '' + conversion: + factor: 746.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: inch per degree Fahrenheit + ConversionFactor: 4,572 x 10⁻² m/K + Symbol: in/°F + CommonCode: K45 + Description: '' + conversion: + factor: 0.04572 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: inch per psi + ConversionFactor: 3,683 959 x 10⁻⁶ m/Pa + Symbol: in/psi + CommonCode: K46 + Description: '' + conversion: + factor: 3.683959e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: inch per second degree Fahrenheit + ConversionFactor: 4,572 x 10⁻² (m/s)/K + Symbol: "(in/s)/°F" + CommonCode: K47 + Description: '' + conversion: + factor: 0.04572 + base_units: + - L12 +- Status: '' + LevelAndCategory: '2' + Name: inch per second psi + ConversionFactor: 3,683 959 x 10⁻⁶ (m/s)/Pa + Symbol: "(in/s)/psi" + CommonCode: K48 + Description: '' + conversion: + factor: 3.683959e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: reciprocal cubic inch + ConversionFactor: 6,102 375 9 x 10⁴ m⁻³ + Symbol: 1/in³ + CommonCode: K49 + Description: '' + conversion: + factor: 61023.759 + base_units: + - C86 +- Status: D + LevelAndCategory: 1S + Name: kilovolt ampere (reactive) + ConversionFactor: 10³ V x A + Symbol: kvar + CommonCode: K5 + Description: Use kilovar (common code KVR) + conversion: + factor: 1000.0 + base_units: + - D44 +- Status: '' + LevelAndCategory: '3.6' + Name: kilobaud + ConversionFactor: 10³ Bd + Symbol: kBd + CommonCode: K50 + Description: A unit of signal transmission speed equal to 10³ (1000) signaling events + per second. + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (mean) + ConversionFactor: 4,190 02 x 10³ J + Symbol: kcal + CommonCode: K51 + Description: '' + conversion: + factor: 4190.02 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (international table) per hour metre degree Celsius + ConversionFactor: 1,163 J/(m x s x K) + Symbol: kcal/(m·h·°C) + CommonCode: K52 + Description: '' + conversion: + factor: 1.163 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (thermochemical) + ConversionFactor: 4,184 x 10³ J + Symbol: kcalth + CommonCode: K53 + Description: '' + conversion: + factor: 4184.0 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (thermochemical) per minute + ConversionFactor: 69,733 33 W + Symbol: kcalth/min + CommonCode: K54 + Description: '' + conversion: + factor: 69.73333 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (thermochemical) per second + ConversionFactor: 4,184 x 10³ W + Symbol: kcalth/s + CommonCode: K55 + Description: '' + conversion: + factor: 4184.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1S + Name: kilomole per hour + ConversionFactor: 2,777 78 x 10⁻¹ mol/s + Symbol: kmol/h + CommonCode: K58 + Description: '' + conversion: + factor: 0.277778 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: kilomole per cubic metre kelvin + ConversionFactor: 10³ (mol/m³)/K + Symbol: "(kmol/m³)/K" + CommonCode: K59 + Description: '' + conversion: + factor: 1000.0 + base_units: + - L28 +- Status: '' + LevelAndCategory: 1M + Name: kilolitre + ConversionFactor: m³ + Symbol: kl + CommonCode: K6 + Description: '' + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: kilomole per cubic metre bar + ConversionFactor: 10⁻² (mol/m³)/Pa + Symbol: "(kmol/m³)/bar" + CommonCode: K60 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: kilomole per minute + ConversionFactor: 16,666 7 mol/s + Symbol: kmol/min + CommonCode: K61 + Description: '' + conversion: + factor: 16.6667 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: litre per litre + ConversionFactor: '1' + Symbol: l/l + CommonCode: K62 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: reciprocal litre + ConversionFactor: 10³ m⁻³ + Symbol: 1/l + CommonCode: K63 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C86 +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per degree Fahrenheit + ConversionFactor: 0,816 466 3 kg/K + Symbol: lb/°F + CommonCode: K64 + Description: '' + conversion: + factor: 0.8164663 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) square foot + ConversionFactor: 4,214 011 x 10⁻² kg x m² + Symbol: lb·ft² + CommonCode: K65 + Description: '' + conversion: + factor: 0.04214011 + base_units: + - B32 +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per day + ConversionFactor: 5,249 912 x 10⁻⁶ kg/s + Symbol: lb/d + CommonCode: K66 + Description: '' + conversion: + factor: 5.249912e-06 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: pound per foot hour + ConversionFactor: 4,133 789 x 10⁻⁴ Pa x s + Symbol: lb/(ft·h) + CommonCode: K67 + Description: '' + conversion: + factor: 0.0004133789 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: pound per foot second + ConversionFactor: 1,488 164 Pa x s + Symbol: lb/(ft·s) + CommonCode: K68 + Description: '' + conversion: + factor: 1.488164 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per cubic foot degree Fahrenheit + ConversionFactor: 28,833 23 (kg/m³)/K + Symbol: "(lb/ft³)/°F" + CommonCode: K69 + Description: '' + conversion: + factor: 28.83323 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per cubic foot psi + ConversionFactor: 2,323 282 x 10⁻³ + Symbol: "(lb/ft³)/psi" + CommonCode: K70 + Description: '' + conversion: + factor: 0.002323282 +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per gallon (UK) + ConversionFactor: 99,776 37 kg/m³ + Symbol: lb/gal (UK) + CommonCode: K71 + Description: '' + conversion: + factor: 99.77637 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per hour degree Fahrenheit + ConversionFactor: 2,267 962 x 10⁻⁴ (kg/s)/K + Symbol: "(lb/h)/°F" + CommonCode: K73 + Description: '' + conversion: + factor: 0.0002267962 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per hour psi + ConversionFactor: 1,827 445 x 10⁻⁸ (kg/s)/Pa + Symbol: "(lb/h)/psi" + CommonCode: K74 + Description: '' + conversion: + factor: 1.827445e-08 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per cubic inch degree Fahrenheit + ConversionFactor: 4,982 384 x 10⁴ (kg/m³)/K + Symbol: "(lb/in³)/°F" + CommonCode: K75 + Description: '' + conversion: + factor: 49823.84 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per cubic inch psi + ConversionFactor: 4,014 632 (kg/m³)/Pa + Symbol: "(lb/in³)/psi" + CommonCode: K76 + Description: '' + conversion: + factor: 4.014632 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per psi + ConversionFactor: 6,578 802 x 10⁻⁵ kg/Pa + Symbol: lb/psi + CommonCode: K77 + Description: '' + conversion: + factor: 6.578802e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per minute + ConversionFactor: 7,559 873 x 10⁻³ kg/s + Symbol: lb/min + CommonCode: K78 + Description: '' + conversion: + factor: 0.007559873 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per minute degree Fahrenheit + ConversionFactor: 1,360 777 x 10⁻² (kg/s)/K + Symbol: lb/(min·°F) + CommonCode: K79 + Description: '' + conversion: + factor: 0.01360777 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per minute psi + ConversionFactor: 1,096 467 x 10⁻⁶ (kg/s)/Pa + Symbol: "(lb/min)/psi" + CommonCode: K80 + Description: '' + conversion: + factor: 1.096467e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per second + ConversionFactor: 0,453 592 4 kg/s + Symbol: lb/s + CommonCode: K81 + Description: '' + conversion: + factor: 0.4535924 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per second degree Fahrenheit + ConversionFactor: 0,816 466 3 (kg/s)/K + Symbol: "(lb/s)/°F" + CommonCode: K82 + Description: '' + conversion: + factor: 0.8164663 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound (avoirdupois) per second psi + ConversionFactor: 6,578 802 x 10⁻⁵ (kg/s)/Pa + Symbol: "(lb/s)/psi" + CommonCode: K83 + Description: '' + conversion: + factor: 6.578802e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound per cubic yard + ConversionFactor: 0,593 276 4 kg/m³ + Symbol: lb/yd³ + CommonCode: K84 + Description: '' + conversion: + factor: 0.5932764 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: pound-force per square foot + ConversionFactor: 47,880 26 Pa + Symbol: lbf/ft² + CommonCode: K85 + Description: '' + conversion: + factor: 47.88026 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: pound-force per square inch degree Fahrenheit + ConversionFactor: 1,241 056 x 10⁴ Pa/K + Symbol: psi/°F + CommonCode: K86 + Description: '' + conversion: + factor: 12410.56 + base_units: + - C64 +- Status: '' + LevelAndCategory: '2' + Name: psi cubic inch per second + ConversionFactor: 0,112 985 Pa x m³/s + Symbol: psi·in³/s + CommonCode: K87 + Description: '' + conversion: + factor: 0.112985 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: psi litre per second + ConversionFactor: 6,894 757 Pa x m³/s + Symbol: psi·l/s + CommonCode: K88 + Description: '' + conversion: + factor: 6.894757 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: psi cubic metre per second + ConversionFactor: 6,894 757 x 10³ Pa x m³/s + Symbol: psi·m³/s + CommonCode: K89 + Description: '' + conversion: + factor: 6894.757 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: psi cubic yard per second + ConversionFactor: 5,271 420 x 10³ Pa x m³/s + Symbol: psi·yd³/s + CommonCode: K90 + Description: '' + conversion: + factor: 5271.42 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound-force second per square foot + ConversionFactor: 47,880 26 Pa x s + Symbol: lbf·s/ft² + CommonCode: K91 + Description: '' + conversion: + factor: 47.88026 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: pound-force second per square inch + ConversionFactor: 6,894 757 x 10³ Pa x s + Symbol: lbf·s/in² + CommonCode: K92 + Description: '' + conversion: + factor: 6894.757 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: reciprocal psi + ConversionFactor: 1,450 377 x 10⁻⁴ Pa⁻¹ + Symbol: 1/psi + CommonCode: K93 + Description: '' + conversion: + factor: 0.0001450377 + base_units: + - C96 +- Status: '' + LevelAndCategory: '2' + Name: quart (UK liquid) per day + ConversionFactor: 1,315 420 x 10⁻⁸ m³/s + Symbol: qt (UK liq.)/d + CommonCode: K94 + Description: '' + conversion: + factor: 1.31542e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (UK liquid) per hour + ConversionFactor: 3,157 008 x 10⁻⁷ m³/s + Symbol: qt (UK liq.)/h + CommonCode: K95 + Description: '' + conversion: + factor: 3.157008e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (UK liquid) per minute + ConversionFactor: 1,894 205 x 10⁻⁵ m³/s + Symbol: qt (UK liq.)/min + CommonCode: K96 + Description: '' + conversion: + factor: 1.894205e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (UK liquid) per second + ConversionFactor: 1,136 523 x 10⁻³ m³/s + Symbol: qt (UK liq.)/s + CommonCode: K97 + Description: '' + conversion: + factor: 0.001136523 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (US liquid) per day + ConversionFactor: 1,095 316 x 10⁻⁸ m³/s + Symbol: qt (US liq.)/d + CommonCode: K98 + Description: '' + conversion: + factor: 1.095316e-08 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (US liquid) per hour + ConversionFactor: 2,628 758 x 10⁻⁷ m³/s + Symbol: qt (US liq.)/h + CommonCode: K99 + Description: '' + conversion: + factor: 2.628758e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '3.9' + Name: cake + ConversionFactor: '' + Symbol: '' + CommonCode: KA + Description: 'A unit of count defining the number of cakes (cake: object shaped + into a flat, compact mass).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: katal + ConversionFactor: s⁻¹ x mol + Symbol: kat + CommonCode: KAT + Description: A unit of catalytic activity defining the catalytic activity of enzymes + and other catalysts. + conversion: + factor: 1.0 + base_units: + - KAT +- Status: '' + LevelAndCategory: '3.9' + Name: kilocharacter + ConversionFactor: '' + Symbol: '' + CommonCode: KB + Description: A unit of information equal to 10³ (1000) characters. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kilobar + ConversionFactor: 10⁸ Pa + Symbol: kbar + CommonCode: KBA + Description: '' + conversion: + factor: 100000000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of choline chloride + ConversionFactor: '' + Symbol: kg C₅ H₁₄ClNO + CommonCode: KCC + Description: A unit of mass equal to one thousand grams of choline chloride. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: kilogram decimal + ConversionFactor: '' + Symbol: '' + CommonCode: KD + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram drained net weight + ConversionFactor: '' + Symbol: kg/net eda + CommonCode: KDW + Description: A unit of mass defining the net number of kilograms of a product, disregarding + the liquid content of the product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: kelvin + ConversionFactor: K + Symbol: K + CommonCode: KEL + Description: 'Refer ISO 80000-5 (Quantities and units — Part 5: Thermodynamics)' + conversion: + factor: 1.0 + base_units: + - CEL + - KEL +- Status: X + LevelAndCategory: '3.9' + Name: kilopacket + ConversionFactor: '' + Symbol: '' + CommonCode: KF + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: keg + ConversionFactor: '' + Symbol: '' + CommonCode: KG + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: kilogram + ConversionFactor: kg + Symbol: kg + CommonCode: KGM + Description: A unit of mass equal to one thousand grams. + conversion: + factor: 1.0 + base_units: + - KGM +- Status: '' + LevelAndCategory: '1' + Name: kilogram per second + ConversionFactor: kg/s + Symbol: kg/s + CommonCode: KGS + Description: '' + conversion: + factor: 1.0 + base_units: + - KGS +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of hydrogen peroxide + ConversionFactor: '' + Symbol: kg H₂O₂ + CommonCode: KHY + Description: A unit of mass equal to one thousand grams of hydrogen peroxide. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilohertz + ConversionFactor: 10³ Hz + Symbol: kHz + CommonCode: KHZ + Description: '' + conversion: + factor: 1000.0 + base_units: + - HTZ +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram per millimetre width + ConversionFactor: 10³ kg/m + Symbol: '' + CommonCode: KI + Description: '' + conversion: + factor: 1000.0 + base_units: + - KL +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram, including container + ConversionFactor: '' + Symbol: '' + CommonCode: KIC + Description: A unit of mass defining the number of kilograms of a product, including + its container. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram, including inner packaging + ConversionFactor: '' + Symbol: '' + CommonCode: KIP + Description: A unit of mass defining the number of kilograms of a product, including + its inner packaging materials. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: kilosegment + ConversionFactor: '' + Symbol: '' + CommonCode: KJ + Description: A unit of information equal to 10³ (1000) segments. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilojoule + ConversionFactor: 10³ J + Symbol: kJ + CommonCode: KJO + Description: '' + conversion: + factor: 1000.0 + base_units: + - JOU +- Status: '' + LevelAndCategory: '1' + Name: kilogram per metre + ConversionFactor: kg/m + Symbol: kg/m + CommonCode: KL + Description: '' + conversion: + factor: 1.0 + base_units: + - KL +- Status: '' + LevelAndCategory: '3.5' + Name: lactic dry material percentage + ConversionFactor: '' + Symbol: '' + CommonCode: KLK + Description: A unit of proportion defining the percentage of dry lactic material + in a product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kilolux + ConversionFactor: 10³ cd x sr / m² + Symbol: klx + CommonCode: KLX + Description: A unit of illuminance equal to one thousand lux. + conversion: + factor: 1000.0 + base_units: + - LUX +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of methylamine + ConversionFactor: '' + Symbol: kg met.am. + CommonCode: KMA + Description: A unit of mass equal to one thousand grams of methylamine. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilometre per hour + ConversionFactor: 0,277 778 m/s + Symbol: km/h + CommonCode: KMH + Description: '' + conversion: + factor: 0.277778 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: 1S + Name: square kilometre + ConversionFactor: 10⁶ m² + Symbol: km² + CommonCode: KMK + Description: '' + conversion: + factor: 1000000.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: '1' + Name: kilogram per cubic metre + ConversionFactor: kg/m³ + Symbol: kg/m³ + CommonCode: KMQ + Description: A unit of weight expressed in kilograms of a substance that fills a + volume of one cubic metre. + conversion: + factor: 1.0 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: 1S + Name: kilometre + ConversionFactor: 10³ m + Symbol: km + CommonCode: KMT + Description: '' + conversion: + factor: 1000.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of nitrogen + ConversionFactor: '' + Symbol: kg N + CommonCode: KNI + Description: A unit of mass equal to one thousand grams of nitrogen. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilonewton per square metre + ConversionFactor: 103pascal + Symbol: kN/m2 + CommonCode: KNM + Description: Pressure expressed in kN/m2. + conversion: + factor: 103.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram named substance + ConversionFactor: '' + Symbol: '' + CommonCode: KNS + Description: A unit of mass equal to one kilogram of a named substance. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: knot + ConversionFactor: 0,514 444 m/s + Symbol: kn + CommonCode: KNT + Description: '' + conversion: + factor: 0.514444 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '3.9' + Name: milliequivalence caustic potash per gram of product + ConversionFactor: '' + Symbol: '' + CommonCode: KO + Description: A unit of count defining the number of milligrams of potassium hydroxide + per gram of product as a measure of the concentration of potassium hydroxide in + the product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilopascal + ConversionFactor: 10³ Pa + Symbol: kPa + CommonCode: KPA + Description: '' + conversion: + factor: 1000.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of potassium hydroxide (caustic potash) + ConversionFactor: '' + Symbol: kg KOH + CommonCode: KPH + Description: A unit of mass equal to one thousand grams of potassium hydroxide (caustic + potash). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of potassium oxide + ConversionFactor: '' + Symbol: kg K₂O + CommonCode: KPO + Description: A unit of mass equal to one thousand grams of potassium oxide. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of phosphorus pentoxide (phosphoric anhydride) + ConversionFactor: '' + Symbol: '' + CommonCode: KPP + Description: A unit of mass equal to one thousand grams of phosphorus pentoxide + phosphoric anhydride. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: kiloroentgen + ConversionFactor: 2,58 x 10⁻¹ C/kg + Symbol: kR + CommonCode: KR + Description: '' + conversion: + factor: 0.258 + base_units: [] +- Status: X + LevelAndCategory: '3.8' + Name: thousand pound per square inch + ConversionFactor: '' + Symbol: '' + CommonCode: KS + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of substance 90 % dry + ConversionFactor: '' + Symbol: kg 90 % sdt + CommonCode: KSD + Description: A unit of mass equal to one thousand grams of a named substance that + is 90% dry. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of sodium hydroxide (caustic soda) + ConversionFactor: '' + Symbol: kg NaOH + CommonCode: KSH + Description: A unit of mass equal to one thousand grams of sodium hydroxide (caustic + soda). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.2' + Name: kit + ConversionFactor: '' + Symbol: '' + CommonCode: KT + Description: 'A unit of count defining the number of kits (kit: tub, barrel or pail).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: 1S + Name: kilometre + ConversionFactor: 10³ m + Symbol: km + CommonCode: KTM + Description: '' + conversion: + factor: 1000.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: kilotonne + ConversionFactor: 10⁶ kg + Symbol: kt + CommonCode: KTN + Description: '' + conversion: + factor: 1000000.0 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of uranium + ConversionFactor: '' + Symbol: kg U + CommonCode: KUR + Description: A unit of mass equal to one thousand grams of uranium. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilovolt - ampere + ConversionFactor: 10³ V x A + Symbol: kV·A + CommonCode: KVA + Description: '' + conversion: + factor: 1000.0 + base_units: + - D44 +- Status: '' + LevelAndCategory: 1S + Name: kilovar + ConversionFactor: 10³ V x A + Symbol: kvar + CommonCode: KVR + Description: '' + conversion: + factor: 1000.0 + base_units: + - D44 +- Status: '' + LevelAndCategory: 1S + Name: kilovolt + ConversionFactor: 10³ V + Symbol: kV + CommonCode: KVT + Description: '' + conversion: + factor: 1000.0 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: 1M + Name: kilogram per millimetre + ConversionFactor: 10³ kg/m + Symbol: kg/mm + CommonCode: KW + Description: '' + conversion: + factor: 1000.0 + base_units: + - KL +- Status: '' + LevelAndCategory: 1S + Name: kilowatt hour + ConversionFactor: 3,6 x 10⁶ J + Symbol: kW·h + CommonCode: KWH + Description: '' + conversion: + factor: 3600000.0 + base_units: + - JOU +- Status: "+" + LevelAndCategory: '2' + Name: kilowatt year + ConversionFactor: '' + Symbol: kW/year + CommonCode: KWY + Description: killowatt year + conversion: + factor: 1.0 +- Status: "¦" + LevelAndCategory: '2' + Name: Kilowatt hour per normalized cubic metre + ConversionFactor: '' + Symbol: '' + CommonCode: KWN + Description: Kilowatt hour per normalized cubic metre (temperature 0°C and pressure + 1013.25 millibars ). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram of tungsten trioxide + ConversionFactor: '' + Symbol: kg WO₃ + CommonCode: KWO + Description: A unit of mass equal to one thousand grams of tungsten trioxide. + conversion: + factor: 1.0 +- Status: "¦" + LevelAndCategory: '2' + Name: Kilowatt hour per standard cubic metre + ConversionFactor: '' + Symbol: '' + CommonCode: KWS + Description: Kilowatt hour per standard cubic metre (temperature 15°C and pressure + 1013.25 millibars). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: kilowatt + ConversionFactor: 10³ W + Symbol: kW + CommonCode: KWT + Description: '' + conversion: + factor: 1000.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: millilitre per kilogram + ConversionFactor: 10⁻⁶ m³/kg + Symbol: ml/kg + CommonCode: KX + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - A39 +- Status: '' + LevelAndCategory: '2' + Name: quart (US liquid) per minute + ConversionFactor: 1,577 255 x 10⁻⁵ m³/s + Symbol: qt (US liq.)/min + CommonCode: L10 + Description: '' + conversion: + factor: 1.577255e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: quart (US liquid) per second + ConversionFactor: 9,463 529 x 10⁻⁴ m³/s + Symbol: qt (US liq.)/s + CommonCode: L11 + Description: '' + conversion: + factor: 0.0009463529 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: metre per second kelvin + ConversionFactor: "(m/s)/K" + Symbol: "(m/s)/K" + CommonCode: L12 + Description: '' + conversion: + factor: 1.0 + base_units: + - L12 +- Status: '' + LevelAndCategory: '2' + Name: metre per second bar + ConversionFactor: 10⁻⁵ (m/s)/Pa + Symbol: "(m/s)/bar" + CommonCode: L13 + Description: '' + conversion: + factor: 1.0e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: square metre hour degree Celsius per kilocalorie (international table) + ConversionFactor: 0,859 845 2 m² x s x K/J + Symbol: m²·h·°C/kcal + CommonCode: L14 + Description: '' + conversion: + factor: 0.8598452 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: millipascal second per kelvin + ConversionFactor: 10⁻³ Pa x s/K + Symbol: mPa·s/K + CommonCode: L15 + Description: '' + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: millipascal second per bar + ConversionFactor: 10⁻⁸ s + Symbol: mPa·s/bar + CommonCode: L16 + Description: '' + conversion: + factor: 1.0e-08 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '2' + Name: milligram per cubic metre kelvin + ConversionFactor: 10⁻⁶ (kg/m³)/K + Symbol: "(mg/m³)/K" + CommonCode: L17 + Description: '' + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: milligram per cubic metre bar + ConversionFactor: 10⁻¹¹ (kg/m³)/Pa + Symbol: "(mg/m³)/bar" + CommonCode: L18 + Description: '' + conversion: + factor: 1.0e-11 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: millilitre per litre + ConversionFactor: 10⁻³ + Symbol: ml/l + CommonCode: L19 + Description: '' + conversion: + factor: 0.001 +- Status: '' + LevelAndCategory: 1M + Name: litre per minute + ConversionFactor: 1,666 67 x 10⁻⁵ m³/s + Symbol: l/min + CommonCode: L2 + Description: '' + conversion: + factor: 1.66667e-05 + base_units: + - MQS +- Status: '' + LevelAndCategory: 1S + Name: reciprocal cubic millimetre + ConversionFactor: 10⁹ m⁻³ + Symbol: 1/mm³ + CommonCode: L20 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - C86 +- Status: '' + LevelAndCategory: 1S + Name: cubic millimetre per cubic metre + ConversionFactor: 10⁹ + Symbol: mm³/m³ + CommonCode: L21 + Description: '' + conversion: + factor: 1000000000.0 +- Status: '' + LevelAndCategory: 1S + Name: mole per hour + ConversionFactor: 2,777 78 x 10⁻⁴ mol/s + Symbol: mol/h + CommonCode: L23 + Description: '' + conversion: + factor: 0.000277778 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: mole per kilogram kelvin + ConversionFactor: "(mol/kg)/K" + Symbol: "(mol/kg)/K" + CommonCode: L24 + Description: '' + conversion: + factor: 1.0 + base_units: + - L24 +- Status: '' + LevelAndCategory: '2' + Name: mole per kilogram bar + ConversionFactor: 10⁻⁵ (mol/kg)/Pa + Symbol: "(mol/kg)/bar" + CommonCode: L25 + Description: '' + conversion: + factor: 1.0e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: mole per litre kelvin + ConversionFactor: 10³ (mol/m³)/K + Symbol: "(mol/l)/K" + CommonCode: L26 + Description: '' + conversion: + factor: 1000.0 + base_units: + - L28 +- Status: '' + LevelAndCategory: '2' + Name: mole per litre bar + ConversionFactor: 10⁻² (mol/m³)/Pa + Symbol: "(mol/l)/bar" + CommonCode: L27 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: mole per cubic metre kelvin + ConversionFactor: "(mol/m³)/K" + Symbol: "(mol/m³)/K" + CommonCode: L28 + Description: '' + conversion: + factor: 1.0 + base_units: + - L28 +- Status: '' + LevelAndCategory: '2' + Name: mole per cubic metre bar + ConversionFactor: 10⁻⁵ (mol/m³)/Pa + Symbol: "(mol/m³)/bar" + CommonCode: L29 + Description: '' + conversion: + factor: 1.0e-05 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: mole per minute + ConversionFactor: 1,666 67 x 10⁻² mol/s + Symbol: mol/min + CommonCode: L30 + Description: '' + conversion: + factor: 0.0166667 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: milliroentgen aequivalent men + ConversionFactor: 10⁻⁵ Sv + Symbol: mrem + CommonCode: L31 + Description: '' + conversion: + factor: 1.0e-05 + base_units: [] +- Status: '' + LevelAndCategory: 1S + Name: nanogram per kilogram + ConversionFactor: 10⁻¹² + Symbol: ng/kg + CommonCode: L32 + Description: '' + conversion: + factor: 1.0e-12 +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per day + ConversionFactor: 3,281 194 x 10⁻⁷kg/s + Symbol: oz/d + CommonCode: L33 + Description: '' + conversion: + factor: 3.281194e-07 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per hour + ConversionFactor: 7,874 867 x 10⁻⁶ kg/s + Symbol: oz/h + CommonCode: L34 + Description: '' + conversion: + factor: 7.874867e-06 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per minute + ConversionFactor: 4,724 92 x 10⁻⁴ kg/s + Symbol: oz/min + CommonCode: L35 + Description: '' + conversion: + factor: 0.000472492 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per second + ConversionFactor: 2,834 952 x 10⁻² kg/s + Symbol: oz/s + CommonCode: L36 + Description: '' + conversion: + factor: 0.02834952 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per gallon (UK) + ConversionFactor: 6,236 023 kg/m³ + Symbol: oz/gal (UK) + CommonCode: L37 + Description: '' + conversion: + factor: 6.236023 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per gallon (US) + ConversionFactor: 7,489 152 kg/m³ + Symbol: oz/gal (US) + CommonCode: L38 + Description: '' + conversion: + factor: 7.489152 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per cubic inch + ConversionFactor: 1,729 994 x 10³ kg/m³ + Symbol: oz/in³ + CommonCode: L39 + Description: '' + conversion: + factor: 1729.994 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois)-force + ConversionFactor: 0,278 013 9 N + Symbol: ozf + CommonCode: L40 + Description: '' + conversion: + factor: 0.2780139 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois)-force inch + ConversionFactor: 7,061 552 x 10⁻³ N x m + Symbol: ozf·in + CommonCode: L41 + Description: '' + conversion: + factor: 0.007061552 + base_units: + - NU +- Status: '' + LevelAndCategory: '2' + Name: picosiemens per metre + ConversionFactor: 10⁻¹² S/m + Symbol: pS/m + CommonCode: L42 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - D10 +- Status: '' + LevelAndCategory: '2' + Name: peck (UK) + ConversionFactor: 9,092 181 x 10⁻³ m³ + Symbol: pk (UK) + CommonCode: L43 + Description: '' + conversion: + factor: 0.009092181 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: peck (UK) per day + ConversionFactor: 1,052 336 x 10⁻⁷ m³/s + Symbol: pk (UK)/d + CommonCode: L44 + Description: '' + conversion: + factor: 1.052336e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (UK) per hour + ConversionFactor: 2,525 606 x 10⁻⁶ m³/s + Symbol: pk (UK)/h + CommonCode: L45 + Description: '' + conversion: + factor: 2.525606e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (UK) per minute + ConversionFactor: 1,515 363 5 x 10⁻⁴ m³/s + Symbol: pk (UK)/min + CommonCode: L46 + Description: '' + conversion: + factor: 0.00015153635 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (UK) per second + ConversionFactor: 9,092 181 x 10⁻³ m³/s + Symbol: pk (UK)/s + CommonCode: L47 + Description: '' + conversion: + factor: 0.009092181 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (US dry) per day + ConversionFactor: 1,019 649 x 10⁻⁷ m³/s + Symbol: pk (US dry)/d + CommonCode: L48 + Description: '' + conversion: + factor: 1.019649e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (US dry) per hour + ConversionFactor: 2,447 158 x 10⁻⁶ m³/s + Symbol: pk (US dry)/h + CommonCode: L49 + Description: '' + conversion: + factor: 2.447158e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (US dry) per minute + ConversionFactor: 1,468 295 x 10⁻⁴ m³/s + Symbol: pk (US dry)/min + CommonCode: L50 + Description: '' + conversion: + factor: 0.0001468295 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: peck (US dry) per second + ConversionFactor: 8,809 768 x 10⁻³ m³/s + Symbol: pk (US dry)/s + CommonCode: L51 + Description: '' + conversion: + factor: 0.008809768 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: psi per psi + ConversionFactor: '1.0' + Symbol: psi/psi + CommonCode: L52 + Description: '' + conversion: + factor: 1.0 + base_units: + - E98 + - F02 + - H60 + - L52 + - M91 +- Status: '' + LevelAndCategory: '2' + Name: pint (UK) per day + ConversionFactor: 6,577 098 x 10⁻⁹ m³/s + Symbol: pt (UK)/d + CommonCode: L53 + Description: '' + conversion: + factor: 6.577098e-09 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (UK) per hour + ConversionFactor: 1,578 504 x 10⁻⁷ m³/s + Symbol: pt (UK)/h + CommonCode: L54 + Description: '' + conversion: + factor: 1.578504e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (UK) per minute + ConversionFactor: 9,471 022 x 10⁻⁶ m³/s + Symbol: pt (UK)/min + CommonCode: L55 + Description: '' + conversion: + factor: 9.471022e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (UK) per second + ConversionFactor: 5,682 613 x 10⁻⁴ m³/s + Symbol: pt (UK)/s + CommonCode: L56 + Description: '' + conversion: + factor: 0.0005682613 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (US liquid) per day + ConversionFactor: 5,476 580 x 10⁻⁹ m³/s + Symbol: pt (US liq.)/d + CommonCode: L57 + Description: '' + conversion: + factor: 5.47658e-09 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (US liquid) per hour + ConversionFactor: 1,314 379 x 10⁻⁷ m³/s + Symbol: pt (US liq.)/h + CommonCode: L58 + Description: '' + conversion: + factor: 1.314379e-07 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (US liquid) per minute + ConversionFactor: 7,886 275 x 10⁻⁶ m³/s + Symbol: pt (US liq.)/min + CommonCode: L59 + Description: '' + conversion: + factor: 7.886275e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: pint (US liquid) per second + ConversionFactor: 4,731 765 x 10⁻⁴ m³/s + Symbol: pt (US liq.)/s + CommonCode: L60 + Description: '' + conversion: + factor: 0.0004731765 + base_units: + - MQS +- Status: X + LevelAndCategory: '2' + Name: pint (US dry) + ConversionFactor: 5,506 105 x 10⁻⁴ m³ + Symbol: pt (US dry) + CommonCode: L61 + Description: Use dry pint (common code PTD) + conversion: + factor: 0.0005506105 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '2' + Name: quart (US dry) + ConversionFactor: 1,101 221 x 10⁻³ m³ + Symbol: qt (US dry) + CommonCode: L62 + Description: Use dry quart (US) (common code QTD) + conversion: + factor: 0.001101221 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: slug per day + ConversionFactor: 1,689 109 x 10⁻⁴ kg/s + Symbol: slug/d + CommonCode: L63 + Description: '' + conversion: + factor: 0.0001689109 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: slug per foot second + ConversionFactor: 47,880 26 Pa x s + Symbol: slug/(ft·s) + CommonCode: L64 + Description: '' + conversion: + factor: 47.88026 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: slug per cubic foot + ConversionFactor: 5,153 788 x 10² kg/m³ + Symbol: slug/ft³ + CommonCode: L65 + Description: '' + conversion: + factor: 515.3788 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: slug per hour + ConversionFactor: 4,053 861 x 10⁻³ kg/s + Symbol: slug/h + CommonCode: L66 + Description: '' + conversion: + factor: 0.004053861 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: slug per minute + ConversionFactor: 0,243 231 7 kg/s + Symbol: slug/min + CommonCode: L67 + Description: '' + conversion: + factor: 0.2432317 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: slug per second + ConversionFactor: 14,593 90 kg/s + Symbol: slug/s + CommonCode: L68 + Description: '' + conversion: + factor: 14.5939 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: tonne per kelvin + ConversionFactor: 10³ kg/K + Symbol: t/K + CommonCode: L69 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per bar + ConversionFactor: 10⁻² kg/Pa + Symbol: t/bar + CommonCode: L70 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per day + ConversionFactor: 1,157 41 x 10⁻² kg/s + Symbol: t/d + CommonCode: L71 + Description: '' + conversion: + factor: 0.0115741 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: tonne per day kelvin + ConversionFactor: 1,157 41 x 10⁻² (kg/s)/K + Symbol: "(t/d)/K" + CommonCode: L72 + Description: '' + conversion: + factor: 0.0115741 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per day bar + ConversionFactor: 1,157 41 x 10⁻⁷ (kg/s)/Pa + Symbol: "(t/d)/bar" + CommonCode: L73 + Description: '' + conversion: + factor: 1.15741e-07 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per hour kelvin + ConversionFactor: 2,777 78 x 10⁻¹ (kg/s)/K + Symbol: "(t/h)/K" + CommonCode: L74 + Description: '' + conversion: + factor: 0.277778 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per hour bar + ConversionFactor: 2,777 78 x 10⁻⁶ (kg/s)/Pa + Symbol: "(t/h)/bar" + CommonCode: L75 + Description: '' + conversion: + factor: 2.77778e-06 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per cubic metre kelvin + ConversionFactor: 10³ (kg/m³)/K + Symbol: "(t/m³)/K" + CommonCode: L76 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per cubic metre bar + ConversionFactor: 10⁻² (kg/m³)/Pa + Symbol: "(t/m³)/bar" + CommonCode: L77 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per minute + ConversionFactor: 16,666 7 kg/s + Symbol: t/min + CommonCode: L78 + Description: '' + conversion: + factor: 16.6667 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: tonne per minute kelvin + ConversionFactor: 16,666 7 (kg/s)/K + Symbol: "(t/min)/K" + CommonCode: L79 + Description: '' + conversion: + factor: 16.6667 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per minute bar + ConversionFactor: 1,666 67 x 10⁻⁴ (kg/s)/Pa + Symbol: "(t/min)/bar" + CommonCode: L80 + Description: '' + conversion: + factor: 0.000166667 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per second + ConversionFactor: 10³ kg/s + Symbol: t/s + CommonCode: L81 + Description: '' + conversion: + factor: 1000.0 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: tonne per second kelvin + ConversionFactor: 10³ (kg/s)/K + Symbol: "(t/s)/K" + CommonCode: L82 + Description: '' + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: tonne per second bar + ConversionFactor: 10⁻² (kg/s)/Pa + Symbol: "(t/s)/bar" + CommonCode: L83 + Description: '' + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: ton (UK shipping) + ConversionFactor: 1,189 3 m³ + Symbol: British shipping ton + CommonCode: L84 + Description: '' + conversion: + factor: 1.1893 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: ton long per day + ConversionFactor: 1,175 980 x 10⁻² kg/s + Symbol: ton (UK)/d + CommonCode: L85 + Description: '' + conversion: + factor: 0.0117598 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ton (US shipping) + ConversionFactor: 1,132 6 m³ + Symbol: "(US) shipping ton" + CommonCode: L86 + Description: '' + conversion: + factor: 1.1326 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: ton short per degree Fahrenheit + ConversionFactor: 1,632 932 x 10³ kg/K + Symbol: ton (US)/°F + CommonCode: L87 + Description: '' + conversion: + factor: 1632.932 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: ton short per day + ConversionFactor: 1,049 982 x 10⁻² kg/s + Symbol: ton (US)/d + CommonCode: L88 + Description: '' + conversion: + factor: 0.01049982 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: ton short per hour degree Fahrenheit + ConversionFactor: 0,453 592 2 kg/s x K + Symbol: ton (US)/(h·°F) + CommonCode: L89 + Description: '' + conversion: + factor: 0.4535922 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: ton short per hour psi + ConversionFactor: 3,654 889 x 10⁻⁵ (kg/s)/Pa + Symbol: "(ton (US)/h)/psi" + CommonCode: L90 + Description: '' + conversion: + factor: 3.654889e-05 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: ton short per psi + ConversionFactor: 0,131 576 + Symbol: ton (US)/psi + CommonCode: L91 + Description: '' + conversion: + factor: 0.131576 +- Status: '' + LevelAndCategory: '2' + Name: ton (UK long) per cubic yard + ConversionFactor: 1,328 939 x 10³ kg/m³ + Symbol: ton.l/yd³ (UK) + CommonCode: L92 + Description: '' + conversion: + factor: 1328.939 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: ton (US short) per cubic yard + ConversionFactor: 1,186 553 x 10³ kg/m³ + Symbol: ton.s/yd³ (US) + CommonCode: L93 + Description: '' + conversion: + factor: 1186.553 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: ton-force (US short) + ConversionFactor: 8,896 443 x 10³ N + Symbol: ton.sh-force + CommonCode: L94 + Description: '' + conversion: + factor: 8896.443 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: common year + ConversionFactor: 3,153 6 x 10⁷ s + Symbol: y (365 days) + CommonCode: L95 + Description: '' + conversion: + factor: 31536000.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '2' + Name: sidereal year + ConversionFactor: 3,155 815 x 10⁷ s + Symbol: y (sidereal) + CommonCode: L96 + Description: '' + conversion: + factor: 31558150.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '2' + Name: yard per degree Fahrenheit + ConversionFactor: 1,645 92 m/K + Symbol: yd/°F + CommonCode: L98 + Description: '' + conversion: + factor: 1.64592 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: yard per psi + ConversionFactor: 1,326 225 x 10⁻⁴ m/Pa + Symbol: yd/psi + CommonCode: L99 + Description: '' + conversion: + factor: 0.0001326225 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound per cubic inch + ConversionFactor: 2,767 990 x 10⁴ kg/m³ + Symbol: lb/in³ + CommonCode: LA + Description: '' + conversion: + factor: 27679.9 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '3.5' + Name: lactose excess percentage + ConversionFactor: '' + Symbol: '' + CommonCode: LAC + Description: A unit of proportion defining the percentage of lactose in a product + that exceeds a defined percentage level. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: pound + ConversionFactor: 0,453 592 37 kg + Symbol: lb + CommonCode: LBR + Description: '' + conversion: + factor: 0.45359237 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.5' + Name: troy pound (US) + ConversionFactor: 373,241 7 g + Symbol: '' + CommonCode: LBT + Description: '' + conversion: + factor: 373.2417 + base_units: [] +- Status: X + LevelAndCategory: '3.1' + Name: linear centimetre + ConversionFactor: '' + Symbol: '' + CommonCode: LC + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: litre per day + ConversionFactor: 1,157 41 x 10⁻⁸ m³/s + Symbol: l/d + CommonCode: LD + Description: '' + conversion: + factor: 1.15741e-08 + base_units: + - MQS +- Status: X + LevelAndCategory: '3.9' + Name: lite + ConversionFactor: '' + Symbol: '' + CommonCode: LE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: leaf + ConversionFactor: '' + Symbol: '' + CommonCode: LEF + Description: A unit of count defining the number of leaves. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: linear foot + ConversionFactor: '' + Symbol: '' + CommonCode: LF + Description: A unit of count defining the number of feet (12-inch) in length of + a uniform width object. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: labour hour + ConversionFactor: '' + Symbol: '' + CommonCode: LH + Description: A unit of time defining the number of labour hours. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: linear inch + ConversionFactor: '' + Symbol: '' + CommonCode: LI + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: large spray + ConversionFactor: '' + Symbol: '' + CommonCode: LJ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: link + ConversionFactor: '' + Symbol: '' + CommonCode: LK + Description: A unit of distance equal to 0.01 chain. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: linear metre + ConversionFactor: '' + Symbol: '' + CommonCode: LM + Description: A unit of count defining the number of metres in length of a uniform + width object. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: length + ConversionFactor: '' + Symbol: '' + CommonCode: LN + Description: A unit of distance defining the linear extent of an item measured from + end to end. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: lot [unit of procurement] + ConversionFactor: '' + Symbol: '' + CommonCode: LO + Description: 'A unit of count defining the number of lots (lot: a collection of + associated items).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: liquid pound + ConversionFactor: '' + Symbol: '' + CommonCode: LP + Description: A unit of mass defining the number of pounds of a liquid substance. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: litre of pure alcohol + ConversionFactor: '' + Symbol: '' + CommonCode: LPA + Description: A unit of volume equal to one litre of pure alcohol. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: layer + ConversionFactor: '' + Symbol: '' + CommonCode: LR + Description: A unit of count defining the number of layers. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: lump sum + ConversionFactor: '' + Symbol: '' + CommonCode: LS + Description: A unit of count defining the number of whole or a complete monetary + amounts. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: ton (UK) or long ton (US) + ConversionFactor: 1,016 047 x 10³ kg + Symbol: ton (UK) + CommonCode: LTN + Description: 'Synonym: gross ton (2240 lb)' + conversion: + factor: 1016.047 + base_units: + - KGM +- Status: '' + LevelAndCategory: '1' + Name: litre + ConversionFactor: 10⁻³ m³ + Symbol: l + CommonCode: LTR + Description: '' + conversion: + factor: 0.001 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.1' + Name: metric ton, lubricating oil + ConversionFactor: '' + Symbol: '' + CommonCode: LUB + Description: A unit of mass defining the number of metric tons of lubricating oil. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: lumen + ConversionFactor: cd x sr + Symbol: lm + CommonCode: LUM + Description: '' + conversion: + factor: 1.0 + base_units: + - LUM +- Status: '' + LevelAndCategory: '1' + Name: lux + ConversionFactor: cd x sr / m² + Symbol: lx + CommonCode: LUX + Description: '' + conversion: + factor: 1.0 + base_units: + - LUX +- Status: X + LevelAndCategory: '3.1' + Name: linear yard per pound + ConversionFactor: '' + Symbol: '' + CommonCode: LX + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: linear yard + ConversionFactor: '' + Symbol: '' + CommonCode: LY + Description: A unit of count defining the number of 36-inch units in length of a + uniform width object. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.6' + Name: magnetic tape + ConversionFactor: '' + Symbol: '' + CommonCode: M0 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: milligram per litre + ConversionFactor: 10⁻³ kg/m³ + Symbol: mg/l + CommonCode: M1 + Description: '' + conversion: + factor: 0.001 + base_units: + - GL + - KMQ +- Status: '' + LevelAndCategory: '2' + Name: reciprocal cubic yard + ConversionFactor: 1,307 951 m⁻³ + Symbol: 1/yd³ + CommonCode: M10 + Description: '' + conversion: + factor: 1.307951 + base_units: + - C86 +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per degree Fahrenheit + ConversionFactor: 1,376 199 m³/K + Symbol: yd³/°F + CommonCode: M11 + Description: '' + conversion: + factor: 1.376199 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per day + ConversionFactor: 8,849 015 x 10⁻⁶ m³/s + Symbol: yd³/d + CommonCode: M12 + Description: '' + conversion: + factor: 8.849015e-06 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per hour + ConversionFactor: 2,123 764 x 10⁻⁴ m³/s + Symbol: yd³/h + CommonCode: M13 + Description: '' + conversion: + factor: 0.0002123764 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per psi + ConversionFactor: 1,108 893 x 10⁻⁴ m³/Pa + Symbol: yd³/psi + CommonCode: M14 + Description: '' + conversion: + factor: 0.0001108893 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per minute + ConversionFactor: 1,274 258 x 10⁻² m³/s + Symbol: yd³/min + CommonCode: M15 + Description: '' + conversion: + factor: 0.01274258 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: cubic yard per second + ConversionFactor: 0,764 554 9 m³/s + Symbol: yd³/s + CommonCode: M16 + Description: '' + conversion: + factor: 0.7645549 + base_units: + - MQS +- Status: '' + LevelAndCategory: '2' + Name: kilohertz metre + ConversionFactor: 10³ Hz x m + Symbol: kHz·m + CommonCode: M17 + Description: '' + conversion: + factor: 1000.0 + base_units: + - H34 +- Status: '' + LevelAndCategory: '2' + Name: gigahertz metre + ConversionFactor: 10⁹ Hz x m + Symbol: GHz·m + CommonCode: M18 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - H34 +- Status: '' + LevelAndCategory: '3' + Name: Beaufort + ConversionFactor: '' + Symbol: Bft + CommonCode: M19 + Description: An empirical measure for describing wind speed based mainly on observed + sea conditions. The Beaufort scale indicates the wind speed by numbers that typically + range from 0 for calm, to 12 for hurricane. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: reciprocal megakelvin or megakelvin to the power minus one + ConversionFactor: 10⁻⁶ K⁻¹ + Symbol: 1/MK + CommonCode: M20 + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: '2' + Name: reciprocal kilovolt - ampere reciprocal hour + ConversionFactor: 2,777 778 x 10⁻⁷ (V x A x s)⁻¹ + Symbol: 1/kVAh + CommonCode: M21 + Description: '' + conversion: + factor: 2.777778e-07 + base_units: + - M30 +- Status: '' + LevelAndCategory: '2' + Name: millilitre per square centimetre minute + ConversionFactor: 2,777 778 x 10⁻⁶ (m³/s)/m² + Symbol: "(ml/min)/cm²" + CommonCode: M22 + Description: '' + conversion: + factor: 2.777778e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: newton per centimetre + ConversionFactor: 10² N/m + Symbol: N/cm + CommonCode: M23 + Description: '' + conversion: + factor: 100.0 + base_units: + - 4P +- Status: '' + LevelAndCategory: 1M + Name: ohm kilometre + ConversionFactor: 10³ Ω x m + Symbol: Ω·km + CommonCode: M24 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C61 +- Status: '' + LevelAndCategory: '3.7' + Name: percent per degree Celsius + ConversionFactor: 10⁻² °C⁻¹ + Symbol: "%/°C" + CommonCode: M25 + Description: A unit of proportion, equal to 0.01, in relation to a temperature of + one degree. + conversion: + factor: 0.01 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: gigaohm per metre + ConversionFactor: 10⁹ Ω/m + Symbol: GΩ/m + CommonCode: M26 + Description: '' + conversion: + factor: 1000000000.0 + base_units: + - H26 +- Status: '' + LevelAndCategory: '2' + Name: megahertz metre + ConversionFactor: 10⁶ Hz x m + Symbol: MHz·m + CommonCode: M27 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - H34 +- Status: '' + LevelAndCategory: 1S + Name: kilogram per kilogram + ConversionFactor: '1' + Symbol: kg/kg + CommonCode: M29 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: reciprocal volt - ampere reciprocal second + ConversionFactor: "(V x A x s)⁻¹" + Symbol: 1/(V·A·s) + CommonCode: M30 + Description: '' + conversion: + factor: 1.0 + base_units: + - M30 +- Status: '' + LevelAndCategory: 1S + Name: kilogram per kilometre + ConversionFactor: 10⁻³ kg/m + Symbol: kg/km + CommonCode: M31 + Description: '' + conversion: + factor: 0.001 + base_units: + - KL +- Status: '' + LevelAndCategory: '2' + Name: pascal second per litre + ConversionFactor: 10³ Pa x s/m³ + Symbol: Pa·s/l + CommonCode: M32 + Description: '' + conversion: + factor: 1000.0 + base_units: + - C66 +- Status: '' + LevelAndCategory: 1S + Name: millimole per litre + ConversionFactor: mol/m³ + Symbol: mmol/l + CommonCode: M33 + Description: '' + conversion: + factor: 1.0 + base_units: + - C36 + - M33 +- Status: '' + LevelAndCategory: 1S + Name: newton metre per square metre + ConversionFactor: N x m/m² + Symbol: N·m/m² + CommonCode: M34 + Description: '' + conversion: + factor: 1.0 + base_units: + - M34 +- Status: '' + LevelAndCategory: 1S + Name: millivolt - ampere + ConversionFactor: 10⁻³ V x A + Symbol: mV·A + CommonCode: M35 + Description: '' + conversion: + factor: 0.001 + base_units: + - D44 +- Status: '' + LevelAndCategory: '3.7' + Name: 30-day month + ConversionFactor: 2,592 000 x 10⁶ s + Symbol: mo (30 days) + CommonCode: M36 + Description: A unit of count defining the number of months expressed in multiples + of 30 days, one day equals 24 hours. + conversion: + factor: 2592000.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.7' + Name: actual/360 + ConversionFactor: 3,110 400 0 x 10⁷ s + Symbol: y (360 days) + CommonCode: M37 + Description: A unit of count defining the number of years expressed in multiples + of 360 days, one day equals 24 hours. + conversion: + factor: 31104000.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1M + Name: kilometre per second squared + ConversionFactor: 10³ m/s² + Symbol: km/s² + CommonCode: M38 + Description: 1000-fold of the SI base unit metre divided by the power of the SI + base unit second by exponent 2. + conversion: + factor: 1000.0 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: 1M + Name: centimetre per second squared + ConversionFactor: 10⁻² m/s² + Symbol: cm/s² + CommonCode: M39 + Description: 0,01-fold of the SI base unit metre divided by the power of the SI + base unit second by exponent 2. + conversion: + factor: 0.01 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '3.9' + Name: monetary value + ConversionFactor: '' + Symbol: '' + CommonCode: M4 + Description: A unit of measure expressed as a monetary amount. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: yard per second squared + ConversionFactor: 9,144 x 10⁻¹ m/s² + Symbol: yd/s² + CommonCode: M40 + Description: Unit of the length according to the Anglo-American and Imperial system + of units divided by the power of the SI base unit second by exponent 2. + conversion: + factor: 0.9144 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: 1M + Name: millimetre per second squared + ConversionFactor: 10⁻³ m/s² + Symbol: mm/s² + CommonCode: M41 + Description: 0,001-fold of the SI base unit metre divided by the power of the SI + base unit second by exponent 2. + conversion: + factor: 0.001 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '2' + Name: mile (statute mile) per second squared + ConversionFactor: 1,609 344 x 10³ m/s² + Symbol: mi/s² + CommonCode: M42 + Description: Unit of the length according to the Imperial system of units divided + by the power of the SI base unit second by exponent 2. + conversion: + factor: 1609.344 + base_units: + - MSK + - P79 +- Status: '' + LevelAndCategory: '2' + Name: mil + ConversionFactor: 9,817 477 x 10⁻⁴ rad + Symbol: mil + CommonCode: M43 + Description: Unit to indicate an angle at military zone, equal to the 6400th part + of the full circle of the 360° or 2·p·rad. + conversion: + factor: 0.0009817477 + base_units: + - C81 +- Status: '' + LevelAndCategory: '2' + Name: revolution + ConversionFactor: 6,283 185 rad + Symbol: rev + CommonCode: M44 + Description: Unit to identify an angle of the full circle of 360° or 2·p·rad (Refer + ISO/TC12 SI Guide). + conversion: + factor: 6.283185 + base_units: + - C81 +- Status: '' + LevelAndCategory: 1M + Name: degree [unit of angle] per second squared + ConversionFactor: 1,745 329 x 10⁻² rad / s + Symbol: "°/s²" + CommonCode: M45 + Description: 360 part of a full circle divided by the power of the SI base unit + second and the exponent 2. + conversion: + factor: 0.01745329 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: revolution per minute + ConversionFactor: 0,104 719 8 rad/s + Symbol: r/min + CommonCode: M46 + Description: Unit of the angular velocity. + conversion: + factor: 0.1047198 + base_units: + - 2A +- Status: '' + LevelAndCategory: '2' + Name: circular mil + ConversionFactor: 5,067 075 x 10⁻¹⁰ m² + Symbol: cmil + CommonCode: M47 + Description: 'Unit of an area, of which the size is given by a diameter of length + of 1 mm (0,001 in) based on the formula: area = p·(diameter/2)².' + conversion: + factor: 5.067075e-10 + base_units: + - MTK +- Status: '' + LevelAndCategory: '2' + Name: square mile (based on U.S. survey foot) + ConversionFactor: 2,589 998 x 10⁶ m² + Symbol: mi² (US survey) + CommonCode: M48 + Description: Unit of the area, which is mainly common in the agriculture and forestry. + conversion: + factor: 2589998.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: '2' + Name: chain (based on U.S. survey foot) + ConversionFactor: 2,011684 x 10 m + Symbol: 'ch (US survey) ' + CommonCode: M49 + Description: Unit of the length according the Anglo-American system of units. + conversion: + factor: 2.011684 + base_units: + - MTR +- Status: '' + LevelAndCategory: 2S + Name: microcurie + ConversionFactor: 3,7 x 10⁴ Bq + Symbol: µCi + CommonCode: M5 + Description: '' + conversion: + factor: 37000.0 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: furlong + ConversionFactor: 2,011 68 x 10² m + Symbol: fur + CommonCode: M50 + Description: 'Unit commonly used in Great Britain at rural distances: 1 furlong + = 40 rods = 10 chains (UK) = 1/8 mile = 1/10 furlong = 220 yards = 660 foot.' + conversion: + factor: 201.168 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: foot (U.S. survey) + ConversionFactor: 3,048 006 x 10⁻¹ m + Symbol: 'ft (US survey) ' + CommonCode: M51 + Description: Unit commonly used in the United States for ordnance survey., + conversion: + factor: 0.3048006 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: mile (based on U.S. survey foot) + ConversionFactor: 1,609347 x 10³ m + Symbol: 'mi (US survey) ' + CommonCode: M52 + Description: Unit commonly used in the United States for ordnance survey. + conversion: + factor: 1609.347 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: metre per pascal + ConversionFactor: kg⁻¹ x m² x s² + Symbol: m/Pa + CommonCode: M53 + Description: SI base unit metre divided by the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M53 +- Status: '' + LevelAndCategory: 1S + Name: metre per radiant + ConversionFactor: m/rad + Symbol: m/rad + CommonCode: M55 + Description: Unit of the translation factor for implementation from rotation to + linear movement. + conversion: + factor: 1.0 + base_units: + - M55 +- Status: '' + LevelAndCategory: '2' + Name: shake + ConversionFactor: 10⁻⁸ s + Symbol: shake + CommonCode: M56 + Description: Unit for a very short period. + conversion: + factor: 1.0e-08 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '2' + Name: mile per minute + ConversionFactor: 26,822 4 m/s + Symbol: mi/min + CommonCode: M57 + Description: Unit of velocity from the Imperial system of units. + conversion: + factor: 26.8224 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: mile per second + ConversionFactor: 1,609 344 x 10³ m/s + Symbol: mi/s + CommonCode: M58 + Description: Unit of the velocity from the Imperial system of units. + conversion: + factor: 1609.344 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: 1S + Name: metre per second pascal + ConversionFactor: m² x kg⁻¹ x s + Symbol: "(m/s)/Pa" + CommonCode: M59 + Description: SI base unit meter divided by the product of SI base unit second and + the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M59 +- Status: '' + LevelAndCategory: '2' + Name: metre per hour + ConversionFactor: 2,777 78 x 10⁻⁴ m/s + Symbol: m/h + CommonCode: M60 + Description: SI base unit metre divided by the unit hour. + conversion: + factor: 0.000277778 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: inch per year + ConversionFactor: 8,048 774 x 10⁻¹⁰ m/s + Symbol: in/y + CommonCode: M61 + Description: Unit of the length according to the Anglo-American and Imperial system + of units divided by the unit common year with 365 days. + conversion: + factor: 8.048774e-10 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: kilometre per second + ConversionFactor: 10³ m/s + Symbol: km/s + CommonCode: M62 + Description: 1000-fold of the SI base unit metre divided by the SI base unit second. + conversion: + factor: 1000.0 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: inch per minute + ConversionFactor: 4,233 333 x 10⁻⁴ m/s + Symbol: in/min + CommonCode: M63 + Description: Unit inch according to the Anglo-American and Imperial system of units + divided by the unit minute. + conversion: + factor: 0.0004233333 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: yard per second + ConversionFactor: 9,144 x 10⁻¹ m/s + Symbol: yd/s + CommonCode: M64 + Description: Unit yard according to the Anglo-American and Imperial system of units + divided by the SI base unit second. + conversion: + factor: 0.9144 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: yard per minute + ConversionFactor: 1,524 x 10⁻² m/s + Symbol: yd/min + CommonCode: M65 + Description: Unit yard according to the Anglo-American and Imperial system of units + divided by the unit minute. + conversion: + factor: 0.01524 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: yard per hour + ConversionFactor: 2,54 x 10⁻⁴ m/s + Symbol: yd/h + CommonCode: M66 + Description: Unit yard according to the Anglo-American and Imperial system of units + divided by the unit hour. + conversion: + factor: 0.000254 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '2' + Name: acre-foot (based on U.S. survey foot) + ConversionFactor: 1,233 489 x 10³ m³ + Symbol: acre-ft (US survey) + CommonCode: M67 + Description: Unit of the volume, which is used in the United States to measure/gauge + the capacity of reservoirs. + conversion: + factor: 1233.489 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: cord (128 ft3) + ConversionFactor: 3,624 556 m³ + Symbol: cord + CommonCode: M68 + Description: Traditional unit of the volume of stacked firewood which has been measured + with a cord. + conversion: + factor: 3.624556 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: cubic mile (UK statute) + ConversionFactor: 4,168 182 x 10⁹ m³ + Symbol: mi³ + CommonCode: M69 + Description: Unit of volume according to the Imperial system of units. + conversion: + factor: 4168182000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: micro-inch + ConversionFactor: 25,4 x 10⁻⁹ m + Symbol: µin + CommonCode: M7 + Description: '' + conversion: + factor: 2.54e-08 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: ton, register + ConversionFactor: 2,831 685 m³ + Symbol: RT + CommonCode: M70 + Description: Traditional unit of the cargo capacity. + conversion: + factor: 2.831685 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: cubic metre per pascal + ConversionFactor: kg⁻¹ x m⁴ x s² + Symbol: m³/Pa + CommonCode: M71 + Description: Power of the SI base unit meter by exponent 3 divided by the derived + SI base unit pascal. + conversion: + factor: 1.0 + base_units: + - M71 +- Status: '' + LevelAndCategory: 1M + Name: bel + ConversionFactor: B + Symbol: B + CommonCode: M72 + Description: Logarithmic relationship to base 10. + conversion: + factor: 1.0 + base_units: + - M72 +- Status: '' + LevelAndCategory: 1M + Name: kilogram per cubic metre pascal + ConversionFactor: m⁻² x s² + Symbol: "(kg/m³)/Pa" + CommonCode: M73 + Description: SI base unit kilogram divided by the product of the power of the SI + base unit metre with exponent 3 and the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M73 +- Status: '' + LevelAndCategory: '2.0' + Name: kilogram per pascal + ConversionFactor: m x s² + Symbol: kg/Pa + CommonCode: M74 + Description: SI base unit kilogram divided by the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M74 +- Status: '' + LevelAndCategory: '2' + Name: kilopound-force + ConversionFactor: 4,448 222 x 10³ N + Symbol: kip + CommonCode: M75 + Description: 1000-fold of the unit of the force pound-force (lbf) according to the + Anglo-American system of units with the relationship. + conversion: + factor: 4448.222 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: poundal + ConversionFactor: 1,382 550 x 10⁻¹ N + Symbol: pdl + CommonCode: M76 + Description: Non SI-conforming unit of the power, which corresponds to a mass of + a pound multiplied with the acceleration of a foot per square second. + conversion: + factor: 0.138255 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: kilogram metre per second squared + ConversionFactor: "(kg x m)/s²" + Symbol: kg·m/s² + CommonCode: M77 + Description: Product of the SI base unit kilogram and the SI base unit metre divided + by the power of the SI base unit second by exponent 2. + conversion: + factor: 1.0 + base_units: + - M77 + - NEW +- Status: '' + LevelAndCategory: '2' + Name: pond + ConversionFactor: 9,806 65 x 10⁻³ N + Symbol: p + CommonCode: M78 + Description: 0,001-fold of the unit of the weight, defined as a mass of 1 kg which + finds out about a weight strength from 1 kp by the gravitational force at sea + level which corresponds to a strength of 9,806 65 newton. + conversion: + factor: 0.00980665 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: square foot per hour + ConversionFactor: 2,580 64 x 10⁻⁵ m²/s + Symbol: ft²/h + CommonCode: M79 + Description: Power of the unit foot according to the Anglo-American and Imperial + system of units by exponent 2 divided by the unit of time hour. + conversion: + factor: 2.58064e-05 + base_units: + - S4 +- Status: '' + LevelAndCategory: '2' + Name: stokes per pascal + ConversionFactor: 10⁻⁴ kg⁻¹ x m³ x s + Symbol: St/Pa + CommonCode: M80 + Description: CGS (Centimetre-Gram-Second system) unit stokes divided by the derived + SI unit pascal. + conversion: + factor: 0.0001 + base_units: + - M82 +- Status: '' + LevelAndCategory: '2' + Name: square centimetre per second + ConversionFactor: 10⁻⁴ m²/s + Symbol: cm²/s + CommonCode: M81 + Description: 0,000 1-fold of the power of the SI base unit metre by exponent 2 divided + by the SI base unit second. + conversion: + factor: 0.0001 + base_units: + - S4 +- Status: '' + LevelAndCategory: '1.0' + Name: square metre per second pascal + ConversionFactor: kg⁻¹ x m³ x s + Symbol: "(m²/s)/Pa" + CommonCode: M82 + Description: Power of the SI base unit metre with the exponent 2 divided by the + SI base unit second and the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M82 +- Status: '' + LevelAndCategory: '2.0' + Name: denier + ConversionFactor: 1,111 111 x 10⁻⁷ kg/m + Symbol: den + CommonCode: M83 + Description: Traditional unit for the indication of the linear mass of textile fibers + and yarns. + conversion: + factor: 1.111111e-07 + base_units: + - KL +- Status: '' + LevelAndCategory: '2' + Name: pound per yard + ConversionFactor: 4,960 546 x 10⁻¹ kg/m + Symbol: lb/yd + CommonCode: M84 + Description: Unit for linear mass according to avoirdupois system of units. + conversion: + factor: 0.4960546 + base_units: + - KL +- Status: '' + LevelAndCategory: '2' + Name: ton, assay + ConversionFactor: 2,916 667 x 10⁻² kg + Symbol: '' + CommonCode: M85 + Description: Non SI-conforming unit of the mass used in the mineralogy to determine + the concentration of precious metals in ore according to the mass of the precious + metal in milligrams in a sample of the mass of an assay sound (number of troy + ounces in a short ton (1 000 lb)). + conversion: + factor: 0.02916667 + base_units: + - KGM +- Status: '' + LevelAndCategory: '2' + Name: pfund + ConversionFactor: 0,5 kg + Symbol: pfd + CommonCode: M86 + Description: Outdated unit of the mass used in Germany. + conversion: + factor: 0.5 + base_units: + - KGM +- Status: '' + LevelAndCategory: 1S + Name: kilogram per second pascal + ConversionFactor: m x s + Symbol: "(kg/s)/Pa" + CommonCode: M87 + Description: SI base unit kilogram divided by the product of the SI base unit second + and the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - M87 +- Status: '' + LevelAndCategory: '2' + Name: tonne per month + ConversionFactor: 3,802 570 537 68 x 10⁻⁴ kg/s + Symbol: t/mo + CommonCode: M88 + Description: Unit tonne divided by the unit month. + conversion: + factor: 0.000380257053768 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2' + Name: tonne per year + ConversionFactor: 3,168 808 781 x 10⁻⁵ kg/s + Symbol: t/y + CommonCode: M89 + Description: Unit tonne divided by the unit year with 365 days. + conversion: + factor: 3.168808781e-05 + base_units: + - KGS +- Status: '' + LevelAndCategory: '3.9' + Name: million Btu per 1000 cubic foot + ConversionFactor: '' + Symbol: MBTU/kft³ + CommonCode: M9 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: kilopound per hour + ConversionFactor: 0,125 997 889 kg/s + Symbol: klb/h + CommonCode: M90 + Description: 1000-fold of the unit of the mass avoirdupois pound according to the + avoirdupois unit system divided by the unit hour. + conversion: + factor: 0.125997889 + base_units: + - KGS +- Status: '' + LevelAndCategory: '2.0' + Name: pound per pound + ConversionFactor: '1.0' + Symbol: lb/lb + CommonCode: M91 + Description: Proportion of the mass consisting of the avoirdupois pound according + to the avoirdupois unit system divided by the avoirdupois pound according to the + avoirdupois unit system. + conversion: + factor: 1.0 + base_units: + - E98 + - F02 + - H60 + - L52 + - M91 +- Status: '' + LevelAndCategory: '2' + Name: pound-force foot + ConversionFactor: 1,355 818 N x m + Symbol: lbf·ft + CommonCode: M92 + Description: Product of the unit pound-force according to the Anglo-American system + of units and the unit foot according to the Anglo-American and the Imperial system + of units. + conversion: + factor: 1.355818 + base_units: + - NU +- Status: '' + LevelAndCategory: 1M + Name: newton metre per radian + ConversionFactor: m² x kg x s⁻² x rad⁻¹ + Symbol: N·m/rad + CommonCode: M93 + Description: Product of the derived SI unit newton and the SI base unit metre divided + by the unit radian. + conversion: + factor: 1.0 + base_units: + - M93 +- Status: '' + LevelAndCategory: 1S + Name: kilogram metre + ConversionFactor: kg x m + Symbol: kg·m + CommonCode: M94 + Description: Unit of imbalance as a product of the SI base unit kilogram and the + SI base unit metre. + conversion: + factor: 1.0 + base_units: + - M94 +- Status: '' + LevelAndCategory: '2' + Name: poundal foot + ConversionFactor: 4,214 011 x 10⁻² N x m + Symbol: pdl·ft + CommonCode: M95 + Description: Product of the non SI-conforming unit of the force poundal and the + unit foot according to the Anglo-American and Imperial system of units . + conversion: + factor: 0.04214011 + base_units: + - NU +- Status: '' + LevelAndCategory: '2' + Name: poundal inch + ConversionFactor: 3,511 677 10⁻³ N x m + Symbol: pdl·in + CommonCode: M96 + Description: Product of the non SI-conforming unit of the force poundal and the + unit inch according to the Anglo-American and Imperial system of units . + conversion: + factor: 1.0 + base_units: + - NU +- Status: '' + LevelAndCategory: '2' + Name: dyne metre + ConversionFactor: 10⁻⁵ N x m + Symbol: dyn·m + CommonCode: M97 + Description: CGS (Centimetre-Gram-Second system) unit of the rotational moment. + conversion: + factor: 1.0e-05 + base_units: + - NU +- Status: '' + LevelAndCategory: 1M + Name: kilogram centimetre per second + ConversionFactor: 10⁻² kg x m/s + Symbol: kg·(cm/s) + CommonCode: M98 + Description: Product of the SI base unit kilogram and the 0,01-fold of the SI base + unit metre divided by the SI base unit second. + conversion: + factor: 0.01 + base_units: + - B31 +- Status: '' + LevelAndCategory: 1M + Name: gram centimetre per second + ConversionFactor: 10⁻⁵ kg x m/s + Symbol: g·(cm/s) + CommonCode: M99 + Description: Product of the 0,001-fold of the SI base unit kilogram and the 0,01-fold + of the SI base unit metre divided by the SI base unit second. + conversion: + factor: 1.0e-05 + base_units: + - B31 +- Status: X + LevelAndCategory: '3.9' + Name: machine per unit + ConversionFactor: '' + Symbol: '' + CommonCode: MA + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: megavolt ampere reactive hour + ConversionFactor: '' + Symbol: Mvar·h + CommonCode: MAH + Description: A unit of electrical reactive power defining the total amount of reactive + power across a power system. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: megalitre + ConversionFactor: 10³ m³ + Symbol: Ml + CommonCode: MAL + Description: '' + conversion: + factor: 1000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: megametre + ConversionFactor: 10⁶ m + Symbol: Mm + CommonCode: MAM + Description: '' + conversion: + factor: 1000000.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: megavar + ConversionFactor: '' + Symbol: Mvar + CommonCode: MAR + Description: A unit of electrical reactive power represented by a current of one + thousand amperes flowing due a potential difference of one thousand volts where + the sine of the phase angle between them is 1. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megawatt + ConversionFactor: 10⁶ W + Symbol: MW + CommonCode: MAW + Description: A unit of power defining the rate of energy transferred or consumed + when a current of 1000 amperes flows due to a potential of 1000 volts at unity + power factor. + conversion: + factor: 1000000.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '3.5' + Name: thousand standard brick equivalent + ConversionFactor: '' + Symbol: '' + CommonCode: MBE + Description: A unit of count defining the number of one thousand brick equivalent + units. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: thousand board foot + ConversionFactor: '' + Symbol: '' + CommonCode: MBF + Description: A unit of volume equal to one thousand board foot. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: millibar + ConversionFactor: 10² Pa + Symbol: mbar + CommonCode: MBR + Description: '' + conversion: + factor: 100.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: 1S + Name: microgram + ConversionFactor: 10⁻⁹ kg + Symbol: µg + CommonCode: MC + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - KGM +- Status: '' + LevelAndCategory: 2S + Name: millicurie + ConversionFactor: 3,7 x 10⁷ Bq + Symbol: mCi + CommonCode: MCU + Description: '' + conversion: + factor: 37000000.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.1' + Name: air dry metric ton + ConversionFactor: '' + Symbol: '' + CommonCode: MD + Description: A unit of count defining the number of metric tons of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: milligram per square foot per side + ConversionFactor: '' + Symbol: '' + CommonCode: MF + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: milligram + ConversionFactor: 10⁻⁶ kg + Symbol: mg + CommonCode: MGM + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - KGM +- Status: '' + LevelAndCategory: 1S + Name: megahertz + ConversionFactor: 10⁶ Hz + Symbol: MHz + CommonCode: MHZ + Description: '' + conversion: + factor: 1000000.0 + base_units: + - HTZ +- Status: '' + LevelAndCategory: '2' + Name: square mile (statute mile) + ConversionFactor: 2,589 988 km² + Symbol: mi² + CommonCode: MIK + Description: '' + conversion: + factor: 2.589988 + base_units: [] +- Status: '' + LevelAndCategory: '3.7' + Name: thousand + ConversionFactor: 10³ + Symbol: '' + CommonCode: MIL + Description: '' + conversion: + factor: 1000.0 +- Status: '' + LevelAndCategory: '1' + Name: minute [unit of time] + ConversionFactor: 60 s + Symbol: min + CommonCode: MIN + Description: '' + conversion: + factor: 60.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.7' + Name: million + ConversionFactor: 10⁶ + Symbol: '' + CommonCode: MIO + Description: '' + conversion: + factor: 1000000.0 +- Status: '' + LevelAndCategory: '3.7' + Name: million international unit + ConversionFactor: '' + Symbol: '' + CommonCode: MIU + Description: A unit of count defining the number of international units in multiples + of 10⁶. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: milligram per square inch + ConversionFactor: '' + Symbol: mg/in² + CommonCode: MK + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: milliard + ConversionFactor: 10⁹ + Symbol: '' + CommonCode: MLD + Description: 'Synonym: billion (US)' + conversion: + factor: 1000000000.0 +- Status: '' + LevelAndCategory: 1S + Name: millilitre + ConversionFactor: 10⁻⁶ m³ + Symbol: ml + CommonCode: MLT + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: square millimetre + ConversionFactor: 10⁻⁶ m² + Symbol: mm² + CommonCode: MMK + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - MTK +- Status: '' + LevelAndCategory: 1S + Name: cubic millimetre + ConversionFactor: 10⁻⁹ m³ + Symbol: mm³ + CommonCode: MMQ + Description: '' + conversion: + factor: 1.0e-09 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: millimetre + ConversionFactor: 10⁻³ m + Symbol: mm + CommonCode: MMT + Description: '' + conversion: + factor: 0.001 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.1' + Name: kilogram, dry weight + ConversionFactor: '' + Symbol: '' + CommonCode: MND + Description: A unit of mass defining the number of kilograms of a product, disregarding + the water content of the product. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: month + ConversionFactor: 2,629 800 x 10⁶ s + Symbol: mo + CommonCode: MON + Description: Unit of time equal to 1/12 of a year of 365,25 days. + conversion: + factor: 2629800.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: megapascal + ConversionFactor: 10⁶ Pa + Symbol: MPa + CommonCode: MPA + Description: '' + conversion: + factor: 1000000.0 + base_units: + - C55 + - PAL +- Status: X + LevelAndCategory: '3.8' + Name: thousand metre + ConversionFactor: 10³m + Symbol: '' + CommonCode: MQ + Description: '' + conversion: + factor: 1000.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per hour + ConversionFactor: 2,777 78 x 10⁻⁴ m³/s + Symbol: m³/h + CommonCode: MQH + Description: '' + conversion: + factor: 0.000277778 + base_units: + - MQS +- Status: '' + LevelAndCategory: '1' + Name: cubic metre per second + ConversionFactor: m³/s + Symbol: m³/s + CommonCode: MQS + Description: '' + conversion: + factor: 1.0 + base_units: + - MQS +- Status: '' + LevelAndCategory: '1' + Name: metre per second squared + ConversionFactor: m/s² + Symbol: m/s² + CommonCode: MSK + Description: '' + conversion: + factor: 1.0 + base_units: + - MSK + - P79 +- Status: X + LevelAndCategory: '3.3' + Name: mat + ConversionFactor: '' + Symbol: '' + CommonCode: MT + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: square metre + ConversionFactor: m² + Symbol: m² + CommonCode: MTK + Description: '' + conversion: + factor: 1.0 + base_units: + - MTK +- Status: '' + LevelAndCategory: '1' + Name: cubic metre + ConversionFactor: m³ + Symbol: m³ + CommonCode: MTQ + Description: 'Synonym: metre cubed' + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '1' + Name: metre + ConversionFactor: m + Symbol: m + CommonCode: MTR + Description: '' + conversion: + factor: 1.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: '1' + Name: metre per second + ConversionFactor: m/s + Symbol: m/s + CommonCode: MTS + Description: '' + conversion: + factor: 1.0 + base_units: + - MTS + - P87 +- Status: X + LevelAndCategory: '3.7' + Name: number of mults + ConversionFactor: '' + Symbol: '' + CommonCode: MV + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: megavolt - ampere + ConversionFactor: 10⁶ V x A + Symbol: MV·A + CommonCode: MVA + Description: '' + conversion: + factor: 1000000.0 + base_units: + - D44 +- Status: '' + LevelAndCategory: 1S + Name: megawatt hour (1000 kW.h) + ConversionFactor: 3,6 x 10⁹ J + Symbol: MW·h + CommonCode: MWH + Description: A unit of power defining the total amount of bulk energy transferred + or consumed. + conversion: + factor: 3600000000.0 + base_units: + - JOU +- Status: '' + LevelAndCategory: '3.9' + Name: pen calorie + ConversionFactor: '' + Symbol: '' + CommonCode: N1 + Description: A unit of count defining the number of calories prescribed daily for + parenteral/enteral therapy. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: pound foot per second + ConversionFactor: 1,382 550 x 10⁻¹ kg x m/s + Symbol: lb·(ft/s) + CommonCode: N10 + Description: Product of the avoirdupois pound according to the avoirdupois unit + system and the unit foot according to the Anglo-American and Imperial system of + units divided by the SI base unit second. + conversion: + factor: 0.138255 + base_units: + - B31 +- Status: '' + LevelAndCategory: '2.0' + Name: pound inch per second + ConversionFactor: 1,152 125 x 10⁻² kg x m/s + Symbol: lb·(in/s) + CommonCode: N11 + Description: Product of the avoirdupois pound according to the avoirdupois unit + system and the unit inch according to the Anglo-American and Imperial system of + units divided by the SI base unit second. + conversion: + factor: 0.01152125 + base_units: + - B31 +- Status: '' + LevelAndCategory: '2' + Name: Pferdestaerke + ConversionFactor: 7,354 988 x 10² W + Symbol: PS + CommonCode: N12 + Description: 'Obsolete unit of the power relating to DIN 1301-3:1979: 1 PS = 735,498 + 75 W.' + conversion: + factor: 735.4988 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: '2' + Name: centimetre of mercury (0 ºC) + ConversionFactor: 1,333 22 x 10³ Pa + Symbol: cmHg (0 ºC) + CommonCode: N13 + Description: Non SI-conforming unit of pressure, at which a value of 1 cmHg meets + the static pressure, which is generated by a mercury at a temperature of 0 °C + with a height of 1 centimetre . + conversion: + factor: 1333.22 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: centimetre of water (4 ºC) + ConversionFactor: 9,806 38 x 10 Pa + Symbol: cmH₂O (4 °C) + CommonCode: N14 + Description: Non SI-conforming unit of pressure, at which a value of 1 cmH2O meets + the static pressure, which is generated by a head of water at a temperature of + 4 °C with a height of 1 centimetre . + conversion: + factor: 9.80638 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: foot of water (39.2 ºF) + ConversionFactor: 2,988 98 x 10³ Pa + Symbol: ftH₂O (39,2 ºF) + CommonCode: N15 + Description: Non SI-conforming unit of pressure according to the Anglo-American + and Imperial system for units, whereas the value of 1 ftH2O is equivalent to the + static pressure, which is generated by a head of water at a temperature 39,2°F + with a height of 1 foot . + conversion: + factor: 2988.98 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: inch of mercury (32 ºF) + ConversionFactor: 3,386 38 x 10³ Pa + Symbol: inHG (32 ºF) + CommonCode: N16 + Description: Non SI-conforming unit of pressure according to the Anglo-American + and Imperial system for units, whereas the value of 1 inHg meets the static pressure, + which is generated by a mercury at a temperature of 32°F with a height of 1 inch. + conversion: + factor: 3386.38 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: inch of mercury (60 ºF) + ConversionFactor: 3,376 85 x 10³ Pa + Symbol: inHg (60 ºF) + CommonCode: N17 + Description: Non SI-conforming unit of pressure according to the Anglo-American + and Imperial system for units, whereas the value of 1 inHg meets the static pressure, + which is generated by a mercury at a temperature of 60°F with a height of 1 inch. + conversion: + factor: 3376.85 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: inch of water (39.2 ºF) + ConversionFactor: 2,490 82 × 10² Pa + Symbol: inH₂O (39,2 ºF) + CommonCode: N18 + Description: Non SI-conforming unit of pressure according to the Anglo-American + and Imperial system for units, whereas the value of 1 inH2O meets the static pressure, + which is generated by a head of water at a temperature of 39,2°F with a height + of 1 inch . + conversion: + factor: 2.49082 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: inch of water (60 ºF) + ConversionFactor: 2,488 4 × 10² Pa + Symbol: inH₂O (60 ºF) + CommonCode: N19 + Description: Non SI-conforming unit of pressure according to the Anglo-American + and Imperial system for units, whereas the value of 1 inH2O meets the static pressure, + which is generated by a head of water at a temperature of 60°F with a height of + 1 inch . + conversion: + factor: 2.4884 + base_units: [] +- Status: X + LevelAndCategory: '3.9' + Name: number of lines + ConversionFactor: '' + Symbol: '' + CommonCode: N2 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: kip per square inch + ConversionFactor: 6,894 757 x 10⁶ Pa + Symbol: ksi + CommonCode: N20 + Description: Non SI-conforming unit of the pressure according to the Anglo-American + system of units as the 1000-fold of the unit of the force pound-force divided + by the power of the unit inch by exponent 2. + conversion: + factor: 6894757.0 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: poundal per square foot + ConversionFactor: 1,488 164 Pa + Symbol: pdl/ft² + CommonCode: N21 + Description: 'Non SI-conforming unit of pressure by the Imperial system of units + according to NIST: 1 pdl/ft² = 1,488 164 Pa.' + conversion: + factor: 1.488164 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) per square inch + ConversionFactor: 4,394 185 x 10 kg/m² + Symbol: oz/in² + CommonCode: N22 + Description: Unit of the surface specific mass (avoirdupois ounce according to the + avoirdupois system of units according to the surface square inch according to + the Anglo-American and Imperial system of units). + conversion: + factor: 4.394185 + base_units: + - '28' +- Status: '' + LevelAndCategory: '2' + Name: conventional metre of water + ConversionFactor: 9,806 65 x 10³ Pa + Symbol: mH₂O + CommonCode: N23 + Description: Not SI-conforming unit of pressure, whereas a value of 1 mH2O is equivalent + to the static pressure, which is produced by one metre high water column . + conversion: + factor: 9806.65 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '2' + Name: gram per square millimetre + ConversionFactor: 10³ kg/m² + Symbol: g/mm² + CommonCode: N24 + Description: 0,001-fold of the SI base unit kilogram divided by the 0.000 001-fold + of the power of the SI base unit meter by exponent 2. + conversion: + factor: 1000.0 + base_units: + - '28' +- Status: '' + LevelAndCategory: '2' + Name: pound per square yard + ConversionFactor: 5,424 919 x 10⁻¹ kg/m² + Symbol: lb/yd² + CommonCode: N25 + Description: Unit for areal-related mass as a unit pound according to the avoirdupois + unit system divided by the power of the unit yard according to the Anglo-American + and Imperial system of units with exponent 2. + conversion: + factor: 0.5424919 + base_units: + - '28' +- Status: '' + LevelAndCategory: '2' + Name: poundal per square inch + ConversionFactor: 2,142 957 × 10² Pa + Symbol: pdl/in² + CommonCode: N26 + Description: Non SI-conforming unit of the pressure according to the Imperial system + of units (poundal by square inch). + conversion: + factor: 2.142957 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: foot to the fourth power + ConversionFactor: 8,630 975 x 10⁻³ m⁴ + Symbol: ft⁴ + CommonCode: N27 + Description: 'Power of the unit foot according to the Anglo-American and Imperial + system of units by exponent 4 according to NIST: 1 ft4 = 8,630 975 m4.' + conversion: + factor: 0.008630975 + base_units: + - B83 +- Status: '' + LevelAndCategory: 1M + Name: cubic decimetre per kilogram + ConversionFactor: 10⁻³ m³ x kg⁻¹ + Symbol: dm³/kg + CommonCode: N28 + Description: 0,001 fold of the power of the SI base unit meter by exponent 3 divided + by the SI based unit kilogram. + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: cubic foot per pound + ConversionFactor: 6,242 796 x 10⁻² m³/kg + Symbol: ft³/lb + CommonCode: N29 + Description: Power of the unit foot according to the Anglo-American and Imperial + system of units by exponent 3 divided by the unit avoirdupois pound according + to the avoirdupois unit system. + conversion: + factor: 0.06242796 + base_units: + - A39 +- Status: '' + LevelAndCategory: '3.5' + Name: print point + ConversionFactor: 0,013 8 in (approx) + Symbol: '' + CommonCode: N3 + Description: '' + conversion: + factor: 0.0138 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: cubic inch per pound + ConversionFactor: 3,612 728 x 10⁻⁵ m³/kg + Symbol: in³/lb + CommonCode: N30 + Description: Power of the unit inch according to the Anglo-American and Imperial + system of units by exponent 3 divided by the avoirdupois pound according to the + avoirdupois unit system . + conversion: + factor: 3.612728e-05 + base_units: + - A39 +- Status: '' + LevelAndCategory: 1M + Name: kilonewton per metre + ConversionFactor: 10³ N/m + Symbol: kN/m + CommonCode: N31 + Description: 1000-fold of the derived SI unit newton divided by the SI base unit + metre. + conversion: + factor: 1000.0 + base_units: + - 4P +- Status: '' + LevelAndCategory: '2.0' + Name: poundal per inch + ConversionFactor: 5,443 110 N/m + Symbol: pdl/in + CommonCode: N32 + Description: Non SI-conforming unit of the surface tension according to the Imperial + unit system as quotient poundal by inch. + conversion: + factor: 5.44311 + base_units: + - 4P +- Status: '' + LevelAndCategory: '2.0' + Name: pound-force per yard + ConversionFactor: 4,864 635 N/m + Symbol: lbf/yd + CommonCode: N33 + Description: Unit of force per unit length based on the Anglo-American system of + units. + conversion: + factor: 4.864635 + base_units: + - 4P +- Status: '' + LevelAndCategory: '2.0' + Name: poundal second per square foot + ConversionFactor: 1,488 164 Pa x s + Symbol: "(pdl/ft²)·s" + CommonCode: N34 + Description: Non SI-conforming unit of viscosity. + conversion: + factor: 1.488164 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2' + Name: poise per pascal + ConversionFactor: 0,1 s + Symbol: P/Pa + CommonCode: N35 + Description: CGS (Centimetre-Gram-Second system) unit poise divided by the derived + SI unit pascal. + conversion: + factor: 0.1 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: 1S + Name: newton second per square metre + ConversionFactor: Pa x s + Symbol: "(N/m²)·s" + CommonCode: N36 + Description: Unit of the dynamic viscosity as a product of unit of the pressure + (newton by square metre) multiplied with the SI base unit second. + conversion: + factor: 1.0 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '1.0' + Name: kilogram per metre second + ConversionFactor: Pa x s + Symbol: kg/(m·s) + CommonCode: N37 + Description: Unit of the dynamic viscosity as a quotient SI base unit kilogram divided + by the SI base unit metre and by the SI base unit second. + conversion: + factor: 1.0 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '1.0' + Name: kilogram per metre minute + ConversionFactor: 1,666 67 × 10⁻² Pa x s + Symbol: kg/(m·min) + CommonCode: N38 + Description: Unit of the dynamic viscosity as a quotient SI base unit kilogram divided + by the SI base unit metre and by the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per metre day + ConversionFactor: 1,157 41 × 10⁻⁵ Pa x s + Symbol: kg/(m·d) + CommonCode: N39 + Description: Unit of the dynamic viscosity as a quotient SI base unit kilogram divided + by the SI base unit metre and by the unit day. + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilogram per metre hour + ConversionFactor: 2,777 78 × 10⁻⁴ Pa x s + Symbol: kg/(m·h) + CommonCode: N40 + Description: Unit of the dynamic viscosity as a quotient SI base unit kilogram divided + by the SI base unit metre and by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gram per centimetre second + ConversionFactor: 0,1 Pa x s + Symbol: g/(cm·s) + CommonCode: N41 + Description: Unit of the dynamic viscosity as a quotient of the 0,001-fold of the + SI base unit kilogram divided by the 0,01-fold of the SI base unit metre and SI + base unit second. + conversion: + factor: 0.1 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2.0' + Name: poundal second per square inch + ConversionFactor: 2,142 957 x 10² Pa x s + Symbol: "(pdl/in²)·s" + CommonCode: N42 + Description: Non SI-conforming unit of dynamic viscosity according to the Imperial + system of units as product unit of the pressure (poundal by square inch) multiplied + by the SI base unit second. + conversion: + factor: 214.2957 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2.0' + Name: pound per foot minute + ConversionFactor: 2,480 273 x 10⁻² Pa x s + Symbol: lb/(ft·min) + CommonCode: N43 + Description: Unit of the dynamic viscosity according to the Anglo-American unit + system. + conversion: + factor: 0.02480273 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: '2.0' + Name: pound per foot day + ConversionFactor: 1,722 412 x 10⁻⁵ Pa x s + Symbol: lb/(ft·d) + CommonCode: N44 + Description: Unit of the dynamic viscosity according to the Anglo-American unit + system. + conversion: + factor: 1.722412e-05 + base_units: + - C65 + - N36 + - N37 +- Status: '' + LevelAndCategory: 1S + Name: cubic metre per second pascal + ConversionFactor: kg⁻¹ x m⁴ x s + Symbol: "(m³/s)/Pa" + CommonCode: N45 + Description: Power of the SI base unit meter by exponent 3 divided by the product + of the SI base unit second and the derived SI base unit pascal. + conversion: + factor: 1.0 + base_units: + - N45 +- Status: '' + LevelAndCategory: '2' + Name: foot poundal + ConversionFactor: 4,214 011 x 10⁻² J + Symbol: ft·pdl + CommonCode: N46 + Description: Unit of the work (force-path). + conversion: + factor: 0.04214011 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2.0' + Name: inch poundal + ConversionFactor: 3,511 677 x 10⁻³ J + Symbol: in·pdl + CommonCode: N47 + Description: Unit of work (force multiplied by path) according to the Imperial system + of units as a product unit inch multiplied by poundal. + conversion: + factor: 0.003511677 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2.0' + Name: watt per square centimetre + ConversionFactor: 10⁴ W/m² + Symbol: W/cm² + CommonCode: N48 + Description: Derived SI unit watt divided by the power of the 0,01-fold the SI base + unit metre by exponent 2. + conversion: + factor: 10000.0 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: watt per square inch + ConversionFactor: 1,550 003 x 10³ W/m² + Symbol: W/in² + CommonCode: N49 + Description: Derived SI unit watt divided by the power of the unit inch according + to the Anglo-American and Imperial system of units by exponent 2. + conversion: + factor: 1550.003 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per square foot hour + ConversionFactor: 3,154 591 W/m² + Symbol: BtuIT/(ft²·h) + CommonCode: N50 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 3.154591 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per square foot hour + ConversionFactor: 3,152 481 W/m² + Symbol: Btuth/(ft²·h) + CommonCode: N51 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 3.152481 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per square foot minute + ConversionFactor: 1,891 489 x 10² W/m² + Symbol: 'Btuth/(ft²·min) ' + CommonCode: N52 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 189.1489 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per square foot second + ConversionFactor: 1,135 653 x 10⁴ W/m² + Symbol: BtuIT/(ft²·s) + CommonCode: N53 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 11356.53 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per square foot second + ConversionFactor: 1,134 893 x 10⁴ W/m² + Symbol: Btuth/(ft²·s) + CommonCode: N54 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 11348.93 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per square inch second + ConversionFactor: 1,634 246 x 10⁶ W/m² + Symbol: BtuIT/(in²·s) + CommonCode: N55 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 1634246.0 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: calorie (thermochemical) per square centimetre minute + ConversionFactor: 6,973 333 x 10² W/m² + Symbol: calth/(cm²·min) + CommonCode: N56 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 697.3333 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: calorie (thermochemical) per square centimetre second + ConversionFactor: 4,184 x 10⁴ W/m² + Symbol: calth/(cm²·s) + CommonCode: N57 + Description: Unit of the surface heat flux according to the Imperial system of units. + conversion: + factor: 41840.0 + base_units: + - D54 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per cubic foot + ConversionFactor: 3,725 895 x10⁴ J/m³ + Symbol: BtuIT/ft³ + CommonCode: N58 + Description: Unit of the energy density according to the Imperial system of units. + conversion: + factor: 3.725895 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per cubic foot + ConversionFactor: 3,723 403 x10⁴ J/m³ + Symbol: Btuth/ft³ + CommonCode: N59 + Description: Unit of the energy density according to the Imperial system of units. + conversion: + factor: 3.723403 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per degree Fahrenheit + ConversionFactor: 1,899 101 x 10³ J/K + Symbol: BtuIT/ºF + CommonCode: N60 + Description: Unit of the heat capacity according to the Imperial system of units. + conversion: + factor: 1899.101 + base_units: + - JE +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per degree Fahrenheit + ConversionFactor: 1,897 830 x 10³ J/K + Symbol: Btuth/ºF + CommonCode: N61 + Description: Unit of the heat capacity according to the Imperial system of units. + conversion: + factor: 1897.83 + base_units: + - JE +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per degree Rankine + ConversionFactor: 1,899 101 x 10³ J/K + Symbol: BtuIT/ºR + CommonCode: N62 + Description: Unit of the heat capacity according to the Imperial system of units. + conversion: + factor: 1899.101 + base_units: + - JE +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per degree Rankine + ConversionFactor: 1,897 830 x 10³ J/K + Symbol: Btuth/ºR + CommonCode: N63 + Description: Unit of the heat capacity according to the Imperial system of units. + conversion: + factor: 1897.83 + base_units: + - JE +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per pound degree Rankine + ConversionFactor: 4,184 x 10³ J/(kg x K) + Symbol: "(Btuth/°R)/lb" + CommonCode: N64 + Description: Unit of the heat capacity (British thermal unit according to the international + table according to the Rankine degree) according to the Imperial system of units + divided by the unit avoirdupois pound according to the avoirdupois system of units. + conversion: + factor: 4184.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: kilocalorie (international table) per gram kelvin + ConversionFactor: 4,186 8 x 10⁶ J/(kg x K) + Symbol: "(kcalIT/K)/g" + CommonCode: N65 + Description: Unit of the mass-related heat capacity as quotient 1000-fold of the + calorie (international table) divided by the product of the 0,001-fold of the + SI base units kilogram and kelvin. + conversion: + factor: 4186800.0 + base_units: + - B11 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (39 ºF) + ConversionFactor: 1,059 67 x 10³ J + Symbol: 'Btu (39 ºF) ' + CommonCode: N66 + Description: Unit of heat energy according to the Imperial system of units in a + reference temperature of 39 °F. + conversion: + factor: 1059.67 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (59 ºF) + ConversionFactor: 1,054 80 x 10³ J + Symbol: Btu (59 ºF) + CommonCode: N67 + Description: Unit of heat energy according to the Imperial system of units in a + reference temperature of 59 °F. + conversion: + factor: 1054.8 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (60 ºF) + ConversionFactor: 1,054 68 x 10³ J + Symbol: 'Btu (60 ºF) ' + CommonCode: N68 + Description: Unit of head energy according to the Imperial system of units at a + reference temperature of 60 °F. + conversion: + factor: 1054.68 + base_units: + - JOU +- Status: '' + LevelAndCategory: '2' + Name: calorie (20 ºC) + ConversionFactor: 4,181 90 + Symbol: cal₂₀ + CommonCode: N69 + Description: Unit for quantity of heat, which is to be required for 1 g air free + water at a constant pressure from 101,325 kPa, to warm up the pressure of standard + atmosphere at sea level, from 19,5 °C on 20,5 °C. + conversion: + factor: 4.1819 +- Status: '' + LevelAndCategory: '2' + Name: quad (1015 BtuIT) + ConversionFactor: 1,055 056 × 10¹⁸ J + Symbol: quad + CommonCode: N70 + Description: Unit of heat energy according to the imperial system of units. + conversion: + factor: 1.055056 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: therm (EC) + ConversionFactor: 1,055 06 × 10⁸ J + Symbol: thm (EC) + CommonCode: N71 + Description: 'Unit of heat energy in commercial use, within the EU defined: 1 thm + (EC) = 100 000 BtuIT.' + conversion: + factor: 1.05506 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: therm (U.S.) + ConversionFactor: 1,054 804 × 10⁸ J + Symbol: thm (US) + CommonCode: N72 + Description: Unit of heat energy in commercial use. + conversion: + factor: 1.054804 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per pound + ConversionFactor: 2,324 444 x 10³ J/kg + Symbol: Btuth/lb + CommonCode: N73 + Description: Unit of the heat energy according to the Imperial system of units divided + the unit avoirdupois pound according to the avoirdupois system of units. + conversion: + factor: 2324.444 + base_units: + - J2 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per hour square foot degree Fahrenheit + ConversionFactor: 5,678 263 W/(m² x K) + Symbol: BtuIT/(h·ft²·ºF) + CommonCode: N74 + Description: Unit of the heat transition coefficient according to the Imperial system + of units. + conversion: + factor: 5.678263 + base_units: + - D55 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per hour square foot degree Fahrenheit + ConversionFactor: 5,674 466 W/(m² x K) + Symbol: Btuth/(h·ft²·ºF) + CommonCode: N75 + Description: Unit of the heat transition coefficient according to the imperial system + of units. + conversion: + factor: 5.674466 + base_units: + - D55 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (international table) per second square foot degree Fahrenheit + ConversionFactor: 2,044 175 x 10⁴ W/(m² x K) + Symbol: BtuIT/(s·ft²·ºF) + CommonCode: N76 + Description: Unit of the heat transition coefficient according to the imperial system + of units. + conversion: + factor: 20441.75 + base_units: + - D55 +- Status: '' + LevelAndCategory: '2' + Name: British thermal unit (thermochemical) per second square foot degree Fahrenheit + ConversionFactor: 2,042 808 x 10⁴ W/(m² x K) + Symbol: 'Btuth/(s·ft²·ºF) ' + CommonCode: N77 + Description: Unit of the heat transition coefficient according to the imperial system + of units. + conversion: + factor: 20428.08 + base_units: + - D55 +- Status: '' + LevelAndCategory: 1M + Name: kilowatt per square metre kelvin + ConversionFactor: 10³ W/(m² x K) + Symbol: kW/(m²·K) + CommonCode: N78 + Description: 1000-fold of the derived SI unit watt divided by the product of the + power of the SI base unit metre by exponent 2 and the SI base unit kelvin. + conversion: + factor: 1000.0 + base_units: + - D55 +- Status: '' + LevelAndCategory: 1S + Name: kelvin per pascal + ConversionFactor: kg⁻¹ x m x s² x K + Symbol: K/Pa + CommonCode: N79 + Description: SI base unit kelvin divided by the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - N79 +- Status: '' + LevelAndCategory: 1M + Name: watt per metre degree Celsius + ConversionFactor: W/(m x K) + Symbol: W/(m·°C) + CommonCode: N80 + Description: Derived SI unit watt divided by the product of the SI base unit metre + and the unit for temperature degree Celsius. + conversion: + factor: 1.0 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: 1M + Name: kilowatt per metre kelvin + ConversionFactor: 10³ W/(m x K) + Symbol: kW/(m·K) + CommonCode: N81 + Description: 1000-fold of the derived SI unit watt divided by the product of the + SI base unit metre and the SI base unit kelvin. + conversion: + factor: 1000.0 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: 1M + Name: kilowatt per metre degree Celsius + ConversionFactor: 10³ W/(m x K) + Symbol: kW/(m·°C) + CommonCode: N82 + Description: 1000-fold of the derived SI unit watt divided by the product of the + SI base unit metre and the unit for temperature degree Celsius. + conversion: + factor: 1000.0 + base_units: + - D53 + - N80 +- Status: '' + LevelAndCategory: '2.0' + Name: metre per degree Celcius metre + ConversionFactor: K⁻¹ + Symbol: m/(°C·m) + CommonCode: N83 + Description: SI base unit metre divided by the product of the unit degree Celsius + and the SI base unit metre. + conversion: + factor: 1.0 + base_units: + - C91 + - N83 +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit hour per British thermal unit (international table) + ConversionFactor: 1,895 634 K/W + Symbol: ºF/(BtuIT/h) + CommonCode: N84 + Description: Non SI-conforming unit of the thermal resistance according to the Imperial + system of units. + conversion: + factor: 1.895634 + base_units: + - B21 +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit hour per British thermal unit (thermochemical) + ConversionFactor: 1,896 903 K/W + Symbol: ºF/(Btuth/h) + CommonCode: N85 + Description: Non SI-conforming unit of the thermal resistance according to the Imperial + system of units. + conversion: + factor: 1.896903 + base_units: + - B21 +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit second per British thermal unit (international table) + ConversionFactor: 5,265 651 x 10⁻⁴ K/W + Symbol: ºF/(BtuIT/s) + CommonCode: N86 + Description: Non SI-conforming unit of the thermal resistance according to the Imperial + system of units. + conversion: + factor: 0.0005265651 + base_units: + - B21 +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit second per British thermal unit (thermochemical) + ConversionFactor: 5,269 175 x 10⁻⁴ K/W + Symbol: ºF/(Btuth/s) + CommonCode: N87 + Description: Non SI-conforming unit of the thermal resistance according to the Imperial + system of units. + conversion: + factor: 0.0005269175 + base_units: + - B21 +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit hour square foot per British thermal unit (international + table) inch + ConversionFactor: 6,933 472 K x m/W + Symbol: ºF·h·ft²/(BtuIT·in) + CommonCode: N88 + Description: Unit of specific thermal resistance according to the Imperial system + of units. + conversion: + factor: 6.933472 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: degree Fahrenheit hour square foot per British thermal unit (thermochemical) + inch + ConversionFactor: 6,938 112 K x m/W + Symbol: ºF·h·ft²/(Btuth·in) + CommonCode: N89 + Description: Unit of specific thermal resistance according to the Imperial system + of units. + conversion: + factor: 6.938112 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilofarad + ConversionFactor: 10³ F + Symbol: kF + CommonCode: N90 + Description: 1000-fold of the derived SI unit farad. + conversion: + factor: 1000.0 + base_units: + - FAR +- Status: '' + LevelAndCategory: '1.0' + Name: reciprocal joule + ConversionFactor: 1/J + Symbol: 1/J + CommonCode: N91 + Description: Reciprocal of the derived SI unit joule. + conversion: + factor: 1.0 + base_units: + - N91 +- Status: '' + LevelAndCategory: 1M + Name: picosiemens + ConversionFactor: 10⁻¹² S + Symbol: pS + CommonCode: N92 + Description: 0,000 000 000 001-fold of the derived SI unit siemens. + conversion: + factor: 1.0e-12 + base_units: + - NQ +- Status: '' + LevelAndCategory: 1M + Name: ampere per pascal + ConversionFactor: kg⁻¹ x m x s² x A + Symbol: A/Pa + CommonCode: N93 + Description: SI base unit ampere divided by the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - N93 +- Status: '' + LevelAndCategory: '2.0' + Name: franklin + ConversionFactor: 3,335 641 x 10⁻¹⁰ C + Symbol: Fr + CommonCode: N94 + Description: CGS (Centimetre-Gram-Second system) unit of the electrical charge, + where the charge amounts to exactly 1 Fr where the force of 1 dyn on an equal + load is performed at a distance of 1 cm. + conversion: + factor: 3.335641e-10 + base_units: + - A8 +- Status: '' + LevelAndCategory: 1M + Name: ampere minute + ConversionFactor: 60 C + Symbol: A·min + CommonCode: N95 + Description: A unit of electric charge defining the amount of charge accumulated + by a steady flow of one ampere for one minute.. + conversion: + factor: 60.0 + base_units: + - A8 +- Status: '' + LevelAndCategory: '2.0' + Name: biot + ConversionFactor: 10¹ A + Symbol: Bi + CommonCode: N96 + Description: CGS (Centimetre-Gram-Second system) unit of the electric power which + is defined by a force of 2 dyn per cm between two parallel conductors of infinite + length with negligible cross-section in the distance of 1 cm. + conversion: + factor: 10.0 + base_units: + - AMP +- Status: '' + LevelAndCategory: '2.0' + Name: gilbert + ConversionFactor: 7,957 747 x 10⁻¹ A + Symbol: Gi + CommonCode: N97 + Description: CGS (Centimetre-Gram-Second system) unit of the magnetomotive force, + which is defined by the work to increase the magnetic potential of a positive + common pol with 1 erg. + conversion: + factor: 0.7957747 + base_units: + - AMP +- Status: '' + LevelAndCategory: 1M + Name: volt per pascal + ConversionFactor: m³ x s⁻¹ x A⁻¹ + Symbol: V/Pa + CommonCode: N98 + Description: Derived SI unit volt divided by the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - N98 +- Status: '' + LevelAndCategory: 1M + Name: picovolt + ConversionFactor: 10⁻¹² V + Symbol: pV + CommonCode: N99 + Description: 0,000 000 000 001-fold of the derived SI unit volt. + conversion: + factor: 1.0e-12 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: 1S + Name: milligram per kilogram + ConversionFactor: 10⁻⁶ 1 + Symbol: mg/kg + CommonCode: NA + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: number of articles + ConversionFactor: '' + Symbol: '' + CommonCode: NAR + Description: 'A unit of count defining the number of articles (article: item).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: barge + ConversionFactor: '' + Symbol: '' + CommonCode: NB + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: number of bobbins + ConversionFactor: '' + Symbol: '' + CommonCode: NBB + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: car + ConversionFactor: '' + Symbol: '' + CommonCode: NC + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: number of cells + ConversionFactor: '' + Symbol: '' + CommonCode: NCL + Description: 'A unit of count defining the number of cells (cell: an enclosed or + circumscribed space, cavity, or volume).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: net barrel + ConversionFactor: '' + Symbol: '' + CommonCode: ND + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: net litre + ConversionFactor: '' + Symbol: '' + CommonCode: NE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: newton + ConversionFactor: "(kg x m)/s²" + Symbol: N + CommonCode: NEW + Description: '' + conversion: + factor: 1.0 + base_units: + - M77 + - NEW +- Status: '' + LevelAndCategory: '3.9' + Name: message + ConversionFactor: '' + Symbol: '' + CommonCode: NF + Description: A unit of count defining the number of messages. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: net gallon (us) + ConversionFactor: '' + Symbol: '' + CommonCode: NG + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: message hour + ConversionFactor: '' + Symbol: '' + CommonCode: NH + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: net imperial gallon + ConversionFactor: '' + Symbol: '' + CommonCode: NI + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: nil + ConversionFactor: '' + Symbol: "()" + CommonCode: NIL + Description: A unit of count defining the number of instances of nothing. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: number of international units + ConversionFactor: '' + Symbol: '' + CommonCode: NIU + Description: A unit of count defining the number of international units. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: number of screens + ConversionFactor: '' + Symbol: '' + CommonCode: NJ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: load + ConversionFactor: '' + Symbol: '' + CommonCode: NL + Description: 'A unit of volume defining the number of loads (load: a quantity of + items carried or processed at one time).' + conversion: + factor: 1.0 +- Status: "¦" + LevelAndCategory: '2' + Name: Normalised cubic metre + ConversionFactor: m3 + Symbol: '' + CommonCode: NM3 + Description: Normalised cubic metre (temperature 0°C and pressure 1013.25 millibars + ) + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '1' + Name: nautical mile + ConversionFactor: 1 852 m + Symbol: n mile + CommonCode: NMI + Description: '' + conversion: + factor: 1852.0 + base_units: + - MTR +- Status: '' + LevelAndCategory: '3.7' + Name: number of packs + ConversionFactor: '' + Symbol: '' + CommonCode: NMP + Description: 'A unit of count defining the number of packs (pack: a collection of + objects packaged together).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: train + ConversionFactor: '' + Symbol: '' + CommonCode: NN + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: number of parcels + ConversionFactor: '' + Symbol: '' + CommonCode: NPL + Description: '' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.7' + Name: number of pairs + ConversionFactor: use pair + Symbol: '' + CommonCode: NPR + Description: 'A unit of count defining the number of pairs (pair: item described + by two''s).' + conversion: + factor: 1.0 + base_units: + - NPR +- Status: '' + LevelAndCategory: '3.7' + Name: number of parts + ConversionFactor: '' + Symbol: '' + CommonCode: NPT + Description: 'A unit of count defining the number of parts (part: component of a + larger entity).' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: mho + ConversionFactor: S + Symbol: '' + CommonCode: NQ + Description: '' + conversion: + factor: 1.0 + base_units: + - NQ +- Status: D + LevelAndCategory: '2' + Name: micromho + ConversionFactor: 10⁻⁶ S + Symbol: '' + CommonCode: NR + Description: '' + conversion: + factor: 1.0e-06 + base_units: + - NQ +- Status: X + LevelAndCategory: '3.7' + Name: number of rolls + ConversionFactor: '' + Symbol: '' + CommonCode: NRL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: net ton + ConversionFactor: '' + Symbol: '' + CommonCode: NT + Description: A unit of mass equal to 2000 pounds, see ton (US). Refer International + Convention on tonnage measurement of Ships. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.4' + Name: net register ton + ConversionFactor: '' + Symbol: '' + CommonCode: NTT + Description: A unit of mass equal to the total cubic footage after deductions, where + 1 register ton is equal to 100 cubic feet. Refer International Convention on tonnage + measurement of Ships. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: newton metre + ConversionFactor: N x m + Symbol: N·m + CommonCode: NU + Description: '' + conversion: + factor: 1.0 + base_units: + - NU +- Status: X + LevelAndCategory: '3.4' + Name: vehicle + ConversionFactor: '' + Symbol: '' + CommonCode: NV + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: part per thousand + ConversionFactor: 1 x 10⁻³ + Symbol: "‰" + CommonCode: NX + Description: 'A unit of proportion equal to 10⁻³. ,Synonym: per mille' + conversion: + factor: 0.001 +- Status: X + LevelAndCategory: '3.5' + Name: pound per air dry metric ton + ConversionFactor: '' + Symbol: '' + CommonCode: NY + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: panel + ConversionFactor: '' + Symbol: '' + CommonCode: OA + Description: 'A unit of count defining the number of panels (panel: a distinct, + usually rectangular, section of a surface).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: ozone depletion equivalent + ConversionFactor: '' + Symbol: '' + CommonCode: ODE + Description: A unit of mass defining the ozone depletion potential in kilograms + of a product relative to the calculated depletion for the reference substance, + Trichlorofluoromethane (CFC-11). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: ODS Grams + ConversionFactor: '' + Symbol: '' + CommonCode: ODG + Description: A unit of measure calculated by multiplying the mass of the substance + in grams and the ozone-depleting potential for the substance., + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: ODS Kilograms + ConversionFactor: '' + Symbol: '' + CommonCode: ODK + Description: A unit of measure calculated by multiplying the mass of the substance + in kilograms and the ozone-depleting potential for the substance. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: ODS Milligrams + ConversionFactor: '' + Symbol: '' + CommonCode: ODM + Description: A unit of measure calculated by multiplying the mass of the substance + in milligrams and the ozone-depleting potential for the substance. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: ohm + ConversionFactor: Ω + Symbol: Ω + CommonCode: OHM + Description: '' + conversion: + factor: 1.0 + base_units: + - OHM +- Status: '' + LevelAndCategory: '2' + Name: ounce per square yard + ConversionFactor: 3,390 575 x 10⁻² kg/m² + Symbol: oz/yd² + CommonCode: 'ON' + Description: '' + conversion: + factor: 0.03390575 + base_units: + - '28' +- Status: '' + LevelAndCategory: '2' + Name: ounce (avoirdupois) + ConversionFactor: 2,834 952 x 10⁻² kg + Symbol: oz + CommonCode: ONZ + Description: '' + conversion: + factor: 0.02834952 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.2' + Name: two pack + ConversionFactor: '' + Symbol: '' + CommonCode: OP + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: oscillations per minute + ConversionFactor: 1.667 x 10-2 /s + Symbol: o/min + CommonCode: OPM + Description: The number of oscillations per minute. + conversion: + factor: 1.0 + base_units: + - BPM + - OPM +- Status: '' + LevelAndCategory: '3.1' + Name: overtime hour + ConversionFactor: '' + Symbol: '' + CommonCode: OT + Description: A unit of time defining the number of overtime hours. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.1' + Name: ounce av + ConversionFactor: '' + Symbol: '' + CommonCode: OZ + Description: A unit of measure equal to 1/16 of a pound or about 28.3495 grams (av + = avoirdupois). Use ounce (common code ONZ). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: fluid ounce (US) + ConversionFactor: 2,957 353 x 10⁻⁵ m³ + Symbol: fl oz (US) + CommonCode: OZA + Description: '' + conversion: + factor: 2.957353e-05 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: fluid ounce (UK) + ConversionFactor: 2,841 306 x 10⁻⁵ m³ + Symbol: fl oz (UK) + CommonCode: OZI + Description: '' + conversion: + factor: 2.841306e-05 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.9' + Name: page - electronic + ConversionFactor: '' + Symbol: '' + CommonCode: P0 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: percent + ConversionFactor: 1 x 10⁻² + Symbol: "% or pct" + CommonCode: P1 + Description: A unit of proportion equal to 0.01. + conversion: + factor: 0.01 +- Status: '' + LevelAndCategory: '1.0' + Name: coulomb per metre + ConversionFactor: m⁻¹ x s x A + Symbol: C/m + CommonCode: P10 + Description: Derived SI unit coulomb divided by the SI base unit metre. + conversion: + factor: 1.0 + base_units: + - P10 +- Status: '' + LevelAndCategory: 1M + Name: kiloweber + ConversionFactor: 10³ Wb + Symbol: kWb + CommonCode: P11 + Description: 1000 fold of the derived SI unit weber. + conversion: + factor: 1000.0 + base_units: + - WEB +- Status: '' + LevelAndCategory: '2.0' + Name: gamma + ConversionFactor: 10⁻⁹ T + Symbol: γ + CommonCode: P12 + Description: Unit of magnetic flow density. + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilotesla + ConversionFactor: 10³ T + Symbol: kT + CommonCode: P13 + Description: 1000-fold of the derived SI unit tesla. + conversion: + factor: 1000.0 + base_units: + - D33 +- Status: '' + LevelAndCategory: '1.0' + Name: joule per second + ConversionFactor: W + Symbol: J/s + CommonCode: P14 + Description: Quotient of the derived SI unit joule divided by the SI base unit second. + conversion: + factor: 1.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: joule per minute + ConversionFactor: 1,666 67 × 10⁻² W + Symbol: J/min + CommonCode: P15 + Description: Quotient from the derived SI unit joule divided by the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: joule per hour + ConversionFactor: 2,777 78 × 10⁻⁴ W + Symbol: J/h + CommonCode: P16 + Description: Quotient from the derived SI unit joule divided by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: joule per day + ConversionFactor: 1,157 41 × 10⁻⁵ W + Symbol: J/d + CommonCode: P17 + Description: Quotient from the derived SI unit joule divided by the unit day. + conversion: + factor: 1.15741 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilojoule per second + ConversionFactor: 10³ W + Symbol: kJ/s + CommonCode: P18 + Description: Quotient from the 1000-fold of the derived SI unit joule divided by + the SI base unit second. + conversion: + factor: 1000.0 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: kilojoule per minute + ConversionFactor: 1,666 67 × 10 W + Symbol: kJ/min + CommonCode: P19 + Description: Quotient from the 1000-fold of the derived SI unit joule divided by + the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: '2' + Name: pound per foot + ConversionFactor: 1,488 164 kg/m + Symbol: lb/ft + CommonCode: P2 + Description: '' + conversion: + factor: 1.488164 + base_units: + - KL +- Status: '' + LevelAndCategory: 1M + Name: kilojoule per hour + ConversionFactor: 2,777 78 x 10⁻¹ W + Symbol: kJ/h + CommonCode: P20 + Description: Quotient from the 1000-fold of the derived SI unit joule divided by + the unit hour. + conversion: + factor: 0.277778 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: kilojoule per day + ConversionFactor: 1,157 41 x 10⁻² W + Symbol: kJ/d + CommonCode: P21 + Description: Quotient from the 1000-fold of the derived SI unit joule divided by + the unit day. + conversion: + factor: 0.0115741 + base_units: + - D46 + - P14 + - WTT +- Status: '' + LevelAndCategory: 1M + Name: nanoohm + ConversionFactor: 10⁻⁹ Ω + Symbol: nΩ + CommonCode: P22 + Description: 0,000 000 001-fold of the derived SI unit ohm. + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: ohm circular-mil per foot + ConversionFactor: 1,662 426 x 10⁻⁹ Ω x m + Symbol: 'Ω·cmil/ft ' + CommonCode: P23 + Description: Unit of resistivity. + conversion: + factor: 1.662426e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilohenry + ConversionFactor: 10³ H + Symbol: kH + CommonCode: P24 + Description: 1000-fold of the derived SI unit henry. + conversion: + factor: 1000.0 + base_units: + - '81' +- Status: '' + LevelAndCategory: '2.0' + Name: lumen per square foot + ConversionFactor: 1,076 391 x 10¹ cd x sr / m² + Symbol: lm/ft² + CommonCode: P25 + Description: Derived SI unit lumen divided by the power of the unit foot according + to the Anglo-American and Imperial system of units by exponent 2. + conversion: + factor: 10.76391 + base_units: + - LUX +- Status: '' + LevelAndCategory: '2.0' + Name: phot + ConversionFactor: 10⁴ cd x sr / m² + Symbol: ph + CommonCode: P26 + Description: CGS (Centimetre-Gram-Second system) unit of luminance, defined as lumen + by square centimetre. + conversion: + factor: 10000.0 + base_units: + - LUX +- Status: '' + LevelAndCategory: '2.0' + Name: footcandle + ConversionFactor: 1,076 391 x 10¹ cd x sr / m² + Symbol: ftc + CommonCode: P27 + Description: Non SI conform traditional unit, defined as density of light which + impinges on a surface which has a distance of one foot from a light source, which + shines with an intensity of an international candle. + conversion: + factor: 10.76391 + base_units: + - LUX +- Status: '' + LevelAndCategory: '2.0' + Name: candela per square inch + ConversionFactor: 1,550 003 x 10³ cd/m² + Symbol: cd/in² + CommonCode: P28 + Description: SI base unit candela divided by the power of unit inch according to + the Anglo-American and Imperial system of units by exponent 2. + conversion: + factor: 1550.003 + base_units: + - A24 +- Status: '' + LevelAndCategory: '2.0' + Name: footlambert + ConversionFactor: 3,426 259 cd/m² + Symbol: ftL + CommonCode: P29 + Description: Unit of the luminance according to the Anglo-American system of units, + defined as emitted or reflected luminance of a lm/ft². + conversion: + factor: 3.426259 + base_units: + - A24 +- Status: X + LevelAndCategory: '3.2' + Name: three pack + ConversionFactor: '' + Symbol: '' + CommonCode: P3 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: lambert + ConversionFactor: 3,183 099 x 10³ cd/m² + Symbol: Lb + CommonCode: P30 + Description: CGS (Centimetre-Gram-Second system) unit of luminance, defined as the + emitted or reflected luminance by one lumen per square centimetre. + conversion: + factor: 3183.099 + base_units: + - A24 +- Status: '' + LevelAndCategory: '2.0' + Name: stilb + ConversionFactor: 10⁴ cd/m² + Symbol: sb + CommonCode: P31 + Description: CGS (Centimetre-Gram-Second system) unit of luminance, defined as emitted + or reflected luminance by one lumen per square centimetre. + conversion: + factor: 10000.0 + base_units: + - A24 +- Status: '' + LevelAndCategory: '2.0' + Name: candela per square foot + ConversionFactor: 1,076 391 x 10 cd/m² + Symbol: cd/ft² + CommonCode: P32 + Description: Base unit SI candela divided by the power of the unit foot according + to the Anglo-American and Imperial system of units by exponent 2. + conversion: + factor: 1.076391 + base_units: + - A24 +- Status: '' + LevelAndCategory: 1M + Name: kilocandela + ConversionFactor: 10³ cd + Symbol: kcd + CommonCode: P33 + Description: 1000-fold of the SI base unit candela. + conversion: + factor: 1000.0 + base_units: + - CDL +- Status: '' + LevelAndCategory: 1M + Name: millicandela + ConversionFactor: 10⁻³ cd + Symbol: mcd + CommonCode: P34 + Description: 0,001-fold of the SI base unit candela. + conversion: + factor: 0.001 + base_units: + - CDL +- Status: '' + LevelAndCategory: '2.0' + Name: Hefner-Kerze + ConversionFactor: 0,903 cd + Symbol: HK + CommonCode: P35 + Description: 'Obsolete, non-legal unit of the power in Germany relating to DIN 1301-3:1979: + 1 HK = 0,903 cd.' + conversion: + factor: 0.903 + base_units: + - CDL +- Status: '' + LevelAndCategory: '2.0' + Name: international candle + ConversionFactor: 1,019 cd + Symbol: IK + CommonCode: P36 + Description: 'Obsolete, non-legal unit of the power in Germany relating to DIN 1301-3:1979: + 1 HK = 1,019 cd.' + conversion: + factor: 1.019 + base_units: + - CDL +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (international table) per square foot + ConversionFactor: 1,135 653 x 10⁴ J/m² + Symbol: BtuIT/ft² + CommonCode: P37 + Description: Unit of the areal-related energy transmission according to the Imperial + system of units. + conversion: + factor: 11356.53 + base_units: + - B13 +- Status: '' + LevelAndCategory: '2.0' + Name: British thermal unit (thermochemical) per square foot + ConversionFactor: 1,134 893 x 10⁴ J/m² + Symbol: Btuth/ft² + CommonCode: P38 + Description: Unit of the areal-related energy transmission according to the Imperial + system of units. + conversion: + factor: 11348.93 + base_units: + - B13 +- Status: '' + LevelAndCategory: '2.0' + Name: calorie (thermochemical) per square centimetre + ConversionFactor: 4,184 x 10⁴ J/m² + Symbol: calth/cm² + CommonCode: P39 + Description: Unit of the areal-related energy transmission according to the Imperial + system of units. + conversion: + factor: 41840.0 + base_units: + - B13 +- Status: X + LevelAndCategory: '3.2' + Name: four pack + ConversionFactor: '' + Symbol: '' + CommonCode: P4 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: langley + ConversionFactor: 4,184 x 10⁴ J/m² + Symbol: Ly + CommonCode: P40 + Description: CGS (Centimetre-Gram-Second system) unit of the areal-related energy + transmission (as a measure of the incident quantity of heat of solar radiation + on the earth's surface). + conversion: + factor: 41840.0 + base_units: + - B13 +- Status: '' + LevelAndCategory: '2' + Name: decade (logarithmic) + ConversionFactor: dec + Symbol: dec + CommonCode: P41 + Description: 1 Dec := log2 10 ˜ 3,32 according to the logarithm for frequency range + between f1 and f2, when f2/f1 = 10. + conversion: + factor: 1.0 + base_units: + - P41 +- Status: '' + LevelAndCategory: '1.0' + Name: pascal squared second + ConversionFactor: m⁻² x kg² x s⁻³ + Symbol: Pa²·s + CommonCode: P42 + Description: Unit of the set as a product of the power of derived SI unit pascal + with exponent 2 and the SI base unit second. + conversion: + factor: 1.0 + base_units: + - P42 +- Status: '' + LevelAndCategory: 1M + Name: bel per metre + ConversionFactor: B/m + Symbol: B/m + CommonCode: P43 + Description: Unit bel divided by the SI base unit metre. + conversion: + factor: 1.0 + base_units: + - P43 +- Status: '' + LevelAndCategory: '2.0' + Name: pound mole + ConversionFactor: 453,592 4 mol + Symbol: lbmol + CommonCode: P44 + Description: Non SI-conforming unit of quantity of a substance relating that one + pound mole of a chemical composition corresponds to the same number of pounds + as the molecular weight of one molecule of this composition in atomic mass units. + conversion: + factor: 453.5924 + base_units: + - C34 +- Status: '' + LevelAndCategory: '2.0' + Name: pound mole per second + ConversionFactor: 4,535 924 x 10² mol/s + Symbol: lbmol/s + CommonCode: P45 + Description: Non SI-conforming unit of the power of the amount of substance non-SI + compliant unit of the molar flux relating that a pound mole of a chemical composition + the same number of pound corresponds like the molecular weight of a molecule of + this composition in atomic mass units. + conversion: + factor: 453.5924 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: pound mole per minute + ConversionFactor: 7,559 873 mol/s + Symbol: lbmol/h + CommonCode: P46 + Description: Non SI-conforming unit of the power of the amount of substance non-SI + compliant unit of the molar flux relating that a pound mole of a chemical composition + the same number of pound corresponds like the molecular weight of a molecule of + this composition in atomic mass units. + conversion: + factor: 7.559873 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilomole per kilogram + ConversionFactor: 10³ mol/kg + Symbol: kmol/kg + CommonCode: P47 + Description: 1000-fold of the SI base unit mol divided by the SI base unit kilogram. + conversion: + factor: 1000.0 + base_units: + - C19 +- Status: '' + LevelAndCategory: '2.0' + Name: pound mole per pound + ConversionFactor: 10³ mol/kg + Symbol: lbmol/lb + CommonCode: P48 + Description: Non SI-conforming unit of the material molar flux divided by the avoirdupois + pound for mass according to the avoirdupois unit system. + conversion: + factor: 1000.0 + base_units: + - C19 +- Status: '' + LevelAndCategory: 1S + Name: newton square metre per ampere + ConversionFactor: m³ x kg x s⁻² x A⁻¹ + Symbol: N·m²/A + CommonCode: P49 + Description: Product of the derived SI unit newton and the power of SI base unit + metre with exponent 2 divided by the SI base unit ampere. + conversion: + factor: 1.0 + base_units: + - P49 + - P50 +- Status: '' + LevelAndCategory: '3.2' + Name: five pack + ConversionFactor: '' + Symbol: '' + CommonCode: P5 + Description: 'A unit of count defining the number of five-packs (five-pack: set + of five items packaged together).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: weber metre + ConversionFactor: m³ x kg x s⁻² x A⁻¹ + Symbol: Wb·m + CommonCode: P50 + Description: Product of the derived SI unit weber and SI base unit metre. + conversion: + factor: 1.0 + base_units: + - P49 + - P50 +- Status: '' + LevelAndCategory: 1S + Name: mol per kilogram pascal + ConversionFactor: m x kg⁻² x s² x mol + Symbol: "(mol/kg)/Pa" + CommonCode: P51 + Description: SI base unit mol divided by the product of the SI base unit kilogram + and the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - P51 +- Status: '' + LevelAndCategory: 1S + Name: mol per cubic metre pascal + ConversionFactor: m⁻² x kg⁻¹ x s² x mol + Symbol: "(mol/m³)/Pa" + CommonCode: P52 + Description: SI base unit mol divided by the product of the power from the SI base + unit metre with exponent 3 and the derived SI unit pascal. + conversion: + factor: 1.0 + base_units: + - P52 +- Status: '' + LevelAndCategory: '2.0' + Name: unit pole + ConversionFactor: 1,256 637 x 10⁻⁷ Wb + Symbol: 'unit pole ' + CommonCode: P53 + Description: CGS (Centimetre-Gram-Second system) unit for magnetic flux of a magnetic + pole (according to the interaction of identical poles of 1 dyn at a distance of + a cm). + conversion: + factor: 1.256637e-07 + base_units: + - WEB +- Status: '' + LevelAndCategory: 1M + Name: milligray per second + ConversionFactor: 10⁻³ Gy/s + Symbol: mGy/s + CommonCode: P54 + Description: 0,001-fold of the derived SI unit gray divided by the SI base unit + second. + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: microgray per second + ConversionFactor: 10⁻⁶ Gy/s + Symbol: µGy/s + CommonCode: P55 + Description: 0,000 001-fold of the derived SI unit gray divided by the SI base unit + second. + conversion: + factor: 1.0e-06 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: nanogray per second + ConversionFactor: 10⁻⁹ Gy/s + Symbol: nGy/s + CommonCode: P56 + Description: 0,000 000 001-fold of the derived SI unit gray divided by the SI base + unit second. + conversion: + factor: 1.0e-09 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gray per minute + ConversionFactor: 1,666 67 × 10⁻² Gy/s + Symbol: Gy/min + CommonCode: P57 + Description: SI derived unit gray divided by the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligray per minute + ConversionFactor: 1,666 67 × 10⁻⁵ Gy/s + Symbol: mGy/min + CommonCode: P58 + Description: 0,001-fold of the derived SI unit gray divided by the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: microgray per minute + ConversionFactor: 1,666 67 × 10⁻⁸ Gy/s + Symbol: µGy/min + CommonCode: P59 + Description: 0,000 001-fold of the derived SI unit gray divided by the unit minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: X + LevelAndCategory: '3.2' + Name: six pack + ConversionFactor: '' + Symbol: '' + CommonCode: P6 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: nanogray per minute + ConversionFactor: 1,666 67 × 10⁻¹¹ Gy/s + Symbol: nGy/min + CommonCode: P60 + Description: 0,000 000 001-fold of the derived SI unit gray divided by the unit + minute. + conversion: + factor: 1.66667 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: gray per hour + ConversionFactor: 2,777 78 × 10⁻⁴ Gy/s + Symbol: Gy/h + CommonCode: P61 + Description: SI derived unit gray divided by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: milligray per hour + ConversionFactor: 2,777 78 × 10⁻⁷ Gy/s + Symbol: mGy/h + CommonCode: P62 + Description: 0,001-fold of the derived SI unit gray divided by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: microgray per hour + ConversionFactor: 2,777 78 × 10⁻¹⁰ Gy/s + Symbol: µGy/h + CommonCode: P63 + Description: 0,000 001-fold of the derived SI unit gray divided by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: nanogray per hour + ConversionFactor: 2,777 78 × 10⁻¹³ Gy/s + Symbol: nGy/h + CommonCode: P64 + Description: 0,000 000 001-fold of the derived SI unit gray divided by the unit + hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: sievert per second + ConversionFactor: Sv/s + Symbol: Sv/s + CommonCode: P65 + Description: Derived SI unit sievert divided by the SI base unit second. + conversion: + factor: 1.0 + base_units: + - P65 +- Status: '' + LevelAndCategory: '2.0' + Name: millisievert per second + ConversionFactor: 10⁻³ Sv/s + Symbol: mSv/s + CommonCode: P66 + Description: 0,001-fold of the derived SI unit sievert divided by the SI base unit + second. + conversion: + factor: 0.001 + base_units: + - P65 +- Status: '' + LevelAndCategory: '2.0' + Name: microsievert per second + ConversionFactor: 10⁻⁶ Sv/s + Symbol: µSv/s + CommonCode: P67 + Description: 0,000 001-fold of the derived SI unit sievert divided by the SI base + unit second. + conversion: + factor: 1.0e-06 + base_units: + - P65 +- Status: '' + LevelAndCategory: '2.0' + Name: nanosievert per second + ConversionFactor: 10⁻⁹ Sv/s + Symbol: nSv/s + CommonCode: P68 + Description: 0,000 000 001-fold of the derived SI unit sievert divided by the SI + base unit second. + conversion: + factor: 1.0e-09 + base_units: + - P65 +- Status: '' + LevelAndCategory: '2.0' + Name: rem per second + ConversionFactor: 10⁻² Sv/s + Symbol: rem/s + CommonCode: P69 + Description: 'Unit for the equivalent tin rate relating to DIN 1301-3:1979: 1 rem/s + = 0,01 J/(kg·s) = 1 Sv/s.' + conversion: + factor: 0.01 + base_units: + - P65 +- Status: X + LevelAndCategory: '3.2' + Name: seven pack + ConversionFactor: '' + Symbol: '' + CommonCode: P7 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2.0' + Name: sievert per hour + ConversionFactor: 2,777 78 × 10⁻⁴ Sv/s + Symbol: Sv/h + CommonCode: P70 + Description: Derived SI unit sievert divided by the unit hour. + conversion: + factor: 2.77778 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: millisievert per hour + ConversionFactor: 0,277 777 778 × 10⁻⁷ Sv/s + Symbol: mSv/h + CommonCode: P71 + Description: 0,001-fold of the derived SI unit sievert divided by the unit hour. + conversion: + factor: 0.277777778 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: microsievert per hour + ConversionFactor: 0,277 777 778 × 10⁻¹⁰ Sv/s + Symbol: µSv/h + CommonCode: P72 + Description: 0,000 001-fold of the derived SI unit sievert divided by the unit hour. + conversion: + factor: 0.277777778 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: nanosievert per hour + ConversionFactor: 0,277 777 778 × 10⁻¹³ Sv/s + Symbol: nSv/h + CommonCode: P73 + Description: 0,000 000 001-fold of the derived SI unit sievert divided by the unit + hour. + conversion: + factor: 0.277777778 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: sievert per minute + ConversionFactor: 0,016 666 Sv/s + Symbol: Sv/min + CommonCode: P74 + Description: Derived SI unit sievert divided by the unit minute. + conversion: + factor: 0.016666 + base_units: + - P65 +- Status: '' + LevelAndCategory: '2.0' + Name: millisievert per minute + ConversionFactor: 1,666 666 667 × 10⁻⁵ Sv/s + Symbol: mSv/min + CommonCode: P75 + Description: 0,001-fold of the derived SI unit sievert divided by the unit minute. + conversion: + factor: 1.666666667 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: microsievert per minute + ConversionFactor: 1,666 666 667 × 10⁻⁸ Sv/s + Symbol: µSv/min + CommonCode: P76 + Description: 0,000 001-fold of the derived SI unit sievert divided by the unit minute. + conversion: + factor: 1.666666667 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: nanosievert per minute + ConversionFactor: 1,666 666 667 × 10⁻¹¹ Sv/s + Symbol: nSv/min + CommonCode: P77 + Description: 0,000 000 001-fold of the derived SI unit sievert divided by the unit + minute. + conversion: + factor: 1.666666667 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: reciprocal square inch + ConversionFactor: 1,550 003 x 10³ m⁻² + Symbol: 1/in² + CommonCode: P78 + Description: Complement of the power of the unit inch according to the Anglo-American + and Imperial system of units by exponent 2. + conversion: + factor: 1550.003 + base_units: + - C93 +- Status: '' + LevelAndCategory: '1.0' + Name: pascal square metre per kilogram + ConversionFactor: m/s² + Symbol: Pa/(kg/m²) + CommonCode: P79 + Description: Unit of the burst index as derived unit for pressure pascal related + to the substance, represented as a quotient from the SI base unit kilogram divided + by the power of the SI base unit metre by exponent 2. + conversion: + factor: 1.0 + base_units: + - MSK + - P79 +- Status: X + LevelAndCategory: '3.2' + Name: eight pack + ConversionFactor: '' + Symbol: '' + CommonCode: P8 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: millipascal per metre + ConversionFactor: 10⁻³ kg/(m² x s²) + Symbol: mPa/m + CommonCode: P80 + Description: 0,001-fold of the derived SI unit pascal divided by the SI base unit + metre. + conversion: + factor: 0.001 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: kilopascal per metre + ConversionFactor: 10³ kg/(m² x s²) + Symbol: kPa/m + CommonCode: P81 + Description: 1000-fold of the derived SI unit pascal divided by the SI base unit + metre. + conversion: + factor: 1000.0 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: hectopascal per metre + ConversionFactor: 10² kg/(m² x s²) + Symbol: hPa/m + CommonCode: P82 + Description: 100-fold of the derived SI unit pascal divided by the SI base unit + metre. + conversion: + factor: 100.0 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: standard atmosphere per metre + ConversionFactor: 1,013 25 x 10⁵ kg/(m² x s²) + Symbol: Atm/m + CommonCode: P83 + Description: Outdated unit of the pressure divided by the SI base unit metre. + conversion: + factor: 101325.0 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: technical atmosphere per metre + ConversionFactor: 9,806 65 x 10⁴ kg/(m² x s²) + Symbol: at/m + CommonCode: P84 + Description: Obsolete and non-legal unit of the pressure which is generated by a + 10 metre water column divided by the SI base unit metre. + conversion: + factor: 98066.5 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: torr per metre + ConversionFactor: 1,333 224 x 10² kg/(m² x s²) + Symbol: Torr/m + CommonCode: P85 + Description: CGS (Centimetre-Gram-Second system) unit of the pressure divided by + the SI base unit metre. + conversion: + factor: 133.3224 + base_units: [] +- Status: '' + LevelAndCategory: '2.0' + Name: psi per inch + ConversionFactor: 2,714 471 x 10⁵ kg/(m² x s²) + Symbol: psi/in + CommonCode: P86 + Description: Compound unit for pressure (pound-force according to the Anglo-American + unit system divided by the power of the unit inch according to the Anglo-American + and Imperial system of units with the exponent 2) divided by the unit inch according + to the Anglo-American and Imperial system of units . + conversion: + factor: 271447.1 + base_units: [] +- Status: '' + LevelAndCategory: 1M + Name: cubic metre per second square metre + ConversionFactor: m/s + Symbol: "(m³/s)/m²" + CommonCode: P87 + Description: Unit of volume flow cubic meters by second related to the transmission + surface in square metres. + conversion: + factor: 1.0 + base_units: + - MTS + - P87 +- Status: '' + LevelAndCategory: '3.5' + Name: rhe + ConversionFactor: 10 m x kg⁻¹ x s + Symbol: rhe + CommonCode: P88 + Description: Non SI-conforming unit of fluidity of dynamic viscosity. + conversion: + factor: 10.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: pound-force foot per inch + ConversionFactor: 53,378 66 m x kg / s² + Symbol: lbf·ft/in + CommonCode: P89 + Description: Unit for length-related rotational moment according to the Anglo-American + and Imperial system of units. + conversion: + factor: 53.37866 + base_units: [] +- Status: X + LevelAndCategory: '3.2' + Name: nine pack + ConversionFactor: '' + Symbol: '' + CommonCode: P9 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: pound-force inch per inch + ConversionFactor: 4,448 222 m x kg / s² + Symbol: lbf·in/in + CommonCode: P90 + Description: Unit for length-related rotational moment according to the Anglo-American + and Imperial system of units. + conversion: + factor: 4.448222 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: perm (0 ºC) + ConversionFactor: 5,721 35 x 10⁻¹¹ kg/(m² x Pa x s) + Symbol: 'perm (0 ºC) ' + CommonCode: P91 + Description: Traditional unit for the ability of a material to allow the transition + of the steam, defined at a temperature of 0 °C as steam transmittance, where the + mass of one grain steam penetrates an area of one foot squared at a pressure from + one inch mercury per hour. + conversion: + factor: 5.72135e-11 + base_units: + - Q28 +- Status: '' + LevelAndCategory: '3.5' + Name: perm (23 ºC) + ConversionFactor: 5,745 25 x 10⁻¹¹ kg/(m² x Pa x s) + Symbol: 'perm (23 ºC) ' + CommonCode: P92 + Description: Traditional unit for the ability of a material to allow the transition + of the steam, defined at a temperature of 23 °C as steam transmittance at which + the mass of one grain of steam penetrates an area of one square foot at a pressure + of one inch mercury per hour. + conversion: + factor: 5.74525e-11 + base_units: + - Q28 +- Status: '' + LevelAndCategory: '3.6' + Name: byte per second + ConversionFactor: byte/s + Symbol: byte/s + CommonCode: P93 + Description: Unit byte divided by the SI base unit second. + conversion: + factor: 1.0 + base_units: + - P93 +- Status: '' + LevelAndCategory: '3.6' + Name: kilobyte per second + ConversionFactor: 10³ byte/s + Symbol: kbyte/s + CommonCode: P94 + Description: 1000-fold of the unit byte divided by the SI base unit second. + conversion: + factor: 1000.0 + base_units: + - P93 +- Status: '' + LevelAndCategory: '3.6' + Name: megabyte per second + ConversionFactor: 10⁶ byte/s + Symbol: Mbyte/s + CommonCode: P95 + Description: 1 000 000-fold of the unit byte divided by the SI base unit second. + conversion: + factor: 1000000.0 + base_units: + - P93 +- Status: '' + LevelAndCategory: '3.5' + Name: reciprocal volt + ConversionFactor: m⁻² x kg⁻¹ x s³ x A + Symbol: 1/V + CommonCode: P96 + Description: Reciprocal of the derived SI unit volt. + conversion: + factor: 1.0 + base_units: + - P96 +- Status: '' + LevelAndCategory: '3.5' + Name: reciprocal radian + ConversionFactor: 1/rad + Symbol: 1/rad + CommonCode: P97 + Description: Reciprocal of the unit radian. + conversion: + factor: 1.0 + base_units: + - P97 +- Status: '' + LevelAndCategory: '3.5' + Name: pascal to the power sum of stoichiometric numbers + ConversionFactor: '' + Symbol: PaΣνB + CommonCode: P98 + Description: Unit of the equilibrium constant on the basis of the pressure(ISO 80000-9:2009, + 9-35.a). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: mole per cubiv metre to the power sum of stoichiometric numbers + ConversionFactor: '' + Symbol: "(mol/m³)∑νB" + CommonCode: P99 + Description: Unit of the equilibrium constant on the basis of the concentration + (ISO 80000-9:2009, 9-36.a). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: packet + ConversionFactor: '' + Symbol: '' + CommonCode: PA + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: pascal + ConversionFactor: Pa + Symbol: Pa + CommonCode: PAL + Description: '' + conversion: + factor: 1.0 + base_units: + - C55 + - PAL +- Status: X + LevelAndCategory: '3.8' + Name: pair inch + ConversionFactor: '' + Symbol: '' + CommonCode: PB + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: pad + ConversionFactor: '' + Symbol: '' + CommonCode: PD + Description: 'A unit of count defining the number of pads (pad: block of paper sheets + fastened together at one end).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: pound equivalent + ConversionFactor: '' + Symbol: '' + CommonCode: PE + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: pallet (lift) + ConversionFactor: '' + Symbol: '' + CommonCode: PF + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: proof litre + ConversionFactor: '' + Symbol: '' + CommonCode: PFL + Description: A unit of volume equal to one litre of proof spirits, or the alcohol + equivalent thereof. Used for measuring the strength of distilled alcoholic liquors, + expressed as a percentage of the alcohol content of a standard mixture at a specific + temperature. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: plate + ConversionFactor: '' + Symbol: '' + CommonCode: PG + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: proof gallon + ConversionFactor: '' + Symbol: '' + CommonCode: PGL + Description: A unit of volume equal to one gallon of proof spirits, or the alcohol + equivalent thereof. Used for measuring the strength of distilled alcoholic liquors, + expressed as a percentage of the alcohol content of a standard mixture at a specific + temperature. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: pitch + ConversionFactor: '' + Symbol: '' + CommonCode: PI + Description: A unit of count defining the number of characters that fit in a horizontal + inch. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: pack + ConversionFactor: '' + Symbol: '' + CommonCode: PK + Description: 'Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet).,Synonym: package' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: pail + ConversionFactor: '' + Symbol: '' + CommonCode: PL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: degree Plato + ConversionFactor: '' + Symbol: "°P" + CommonCode: PLA + Description: A unit of proportion defining the sugar content of a product, especially + in relation to beer. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: pound percentage + ConversionFactor: '' + Symbol: '' + CommonCode: PM + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: pound net + ConversionFactor: '' + Symbol: '' + CommonCode: PN + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: pound per inch of length + ConversionFactor: 1,785 797 x 10¹ kg/m + Symbol: lb/in + CommonCode: PO + Description: '' + conversion: + factor: 17.85797 + base_units: + - KL +- Status: '' + LevelAndCategory: '3.5' + Name: page per inch + ConversionFactor: '' + Symbol: ppi + CommonCode: PQ + Description: A unit of quantity defining the degree of thickness of a bound publication, + expressed as the number of pages per inch of thickness. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: pair + ConversionFactor: '2' + Symbol: '' + CommonCode: PR + Description: 'A unit of count defining the number of pairs (pair: item described + by two''s).' + conversion: + factor: 2.0 +- Status: '' + LevelAndCategory: '2' + Name: pound-force per square inch + ConversionFactor: 6,894 757 x 10³ Pa + Symbol: lbf/in² + CommonCode: PS + Description: '' + conversion: + factor: 6894.757 + base_units: + - C55 + - PAL +- Status: D + LevelAndCategory: '2' + Name: pint (US) + ConversionFactor: 4, 731 76 x 10⁻⁴ m³ + Symbol: pt (US) + CommonCode: PT + Description: Use liquid pint (common code PTL) + conversion: + factor: 0.000473176 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: dry pint (US) + ConversionFactor: 5,506 105 x 10⁻⁴ m³ + Symbol: dry pt (US) + CommonCode: PTD + Description: '' + conversion: + factor: 0.0005506105 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: pint (UK) + ConversionFactor: 5, 682 61 x 10⁻⁴ m³ + Symbol: pt (UK) + CommonCode: PTI + Description: '' + conversion: + factor: 0.000568261 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: liquid pint (US) + ConversionFactor: 4, 731 765 x 10⁻⁴ m³ + Symbol: liq pt (US) + CommonCode: PTL + Description: '' + conversion: + factor: 0.0004731765 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.5' + Name: portion + ConversionFactor: '' + Symbol: '' + CommonCode: PTN + Description: A quantity of allowance of food allotted to, or enough for, one person. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: tray / tray pack + ConversionFactor: '' + Symbol: '' + CommonCode: PU + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: half pint (US) + ConversionFactor: '' + Symbol: '' + CommonCode: PV + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: pound per inch of width + ConversionFactor: '' + Symbol: '' + CommonCode: PW + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: peck dry (US) + ConversionFactor: '' + Symbol: '' + CommonCode: PY + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: peck dry (UK) + ConversionFactor: '' + Symbol: '' + CommonCode: PZ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: joule per tesla + ConversionFactor: m² x A + Symbol: J/T + CommonCode: Q10 + Description: Unit of the magnetic dipole moment of the molecule as derived SI unit + joule divided by the derived SI unit tesla. + conversion: + factor: 1.0 + base_units: + - Q10 +- Status: '' + LevelAndCategory: '3.6' + Name: erlang + ConversionFactor: 1 E + Symbol: E + CommonCode: Q11 + Description: Unit of the market value according to the feature of a single feature + as a statistical measurement of the existing utilization. + conversion: + factor: 1.0 + base_units: + - Q11 +- Status: '' + LevelAndCategory: '3.6' + Name: octet + ConversionFactor: 8 bit + Symbol: o + CommonCode: Q12 + Description: 'Synonym for byte: 1 octet = 8 bit = 1 byte.' + conversion: + factor: 8.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.6' + Name: octet per second + ConversionFactor: 8 bit/s + Symbol: o/s + CommonCode: Q13 + Description: Unit octet divided by the SI base unit second. + conversion: + factor: 8.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.6' + Name: shannon + ConversionFactor: '' + Symbol: Sh + CommonCode: Q14 + Description: Logarithmic unit for information equal to the content of decision of + a sentence of two mutually exclusive events, expressed as a logarithm to base + 2. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: hartley + ConversionFactor: '' + Symbol: Hart + CommonCode: Q15 + Description: Logarithmic unit for information equal to the content of decision of + a sentence of ten mutually exclusive events, expressed as a logarithm to base + 10. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.6' + Name: natural unit of information + ConversionFactor: nat + Symbol: nat + CommonCode: Q16 + Description: Logarithmic unit for information equal to the content of decision of + a sentence of ,718 281 828 459 mutually exclusive events, expressed as a logarithm + to base Euler value e. + conversion: + factor: 1.0 + base_units: + - Q16 +- Status: '' + LevelAndCategory: '3.6' + Name: shannon per second + ConversionFactor: Sh/s + Symbol: Sh/s + CommonCode: Q17 + Description: Time related logarithmic unit for information equal to the content + of decision of a sentence of two mutually exclusive events, expressed as a logarithm + to base 2. + conversion: + factor: 1.0 + base_units: + - Q17 +- Status: '' + LevelAndCategory: '3.6' + Name: hartley per second + ConversionFactor: Hart/s + Symbol: Hart/s + CommonCode: Q18 + Description: Time related logarithmic unit for information equal to the content + of decision of a sentence of ten mutually exclusive events, expressed as a logarithm + to base 10. + conversion: + factor: 1.0 + base_units: + - Q18 +- Status: '' + LevelAndCategory: '3.6' + Name: natural unit of information per second + ConversionFactor: nat/s + Symbol: nat/s + CommonCode: Q19 + Description: Time related logarithmic unit for information equal to the content + of decision of a sentence of 2,718 281 828 459 mutually exclusive events, expressed + as a logarithm to base of the Euler value e. + conversion: + factor: 1.0 + base_units: + - Q19 +- Status: '' + LevelAndCategory: '3.5' + Name: second per kilogramm + ConversionFactor: kg⁻¹ x s + Symbol: s/kg + CommonCode: Q20 + Description: Unit of the Einstein transition probability for spontaneous or inducing + emissions and absorption according to ISO 80000-7:2008, expressed as SI base unit + second divided by the SI base unit kilogram. + conversion: + factor: 1.0 + base_units: + - Q20 +- Status: '' + LevelAndCategory: '3.5' + Name: watt square metre + ConversionFactor: m⁴ x kg x s⁻³ + Symbol: W·m² + CommonCode: Q21 + Description: Unit of the first radiation constants c1 = 2·p·h·c0², the value of + which is 3,741 771 18·10?¹6-fold that of the comparative value of the product + of the derived SI unit watt multiplied with the power of the SI base unit metre + with the exponent 2. + conversion: + factor: 1.0 + base_units: + - Q21 +- Status: '' + LevelAndCategory: '3.5' + Name: second per radian cubic metre + ConversionFactor: m⁻³ x s x rad⁻¹ + Symbol: 1/(Hz·rad·m³) + CommonCode: Q22 + Description: Unit of the density of states as an expression of angular frequency + as complement of the product of hertz and radiant and the power of SI base unit + metre by exponent 3 . + conversion: + factor: 1.0 + base_units: + - Q22 +- Status: '' + LevelAndCategory: '3.5' + Name: weber to the power minus one + ConversionFactor: m⁻² x kg⁻¹ x s² x A + Symbol: 1/Wb + CommonCode: Q23 + Description: Complement of the derived SI unit weber as unit of the Josephson constant, + which value is equal to the 384 597,891-fold of the reference value gigahertz + divided by volt. + conversion: + factor: 1.0 + base_units: + - Q23 +- Status: '' + LevelAndCategory: '3.5' + Name: reciprocal inch + ConversionFactor: 39,370 08 m⁻¹ + Symbol: 1/in + CommonCode: Q24 + Description: Complement of the unit inch according to the Anglo-American and Imperial + system of units. + conversion: + factor: 39.37008 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.5' + Name: dioptre + ConversionFactor: m⁻¹ + Symbol: dpt + CommonCode: Q25 + Description: 'Unit used at the statement of relative refractive indexes of optical + systems as complement of the focal length with correspondence to: 1 dpt = 1/m.' + conversion: + factor: 1.0 + base_units: + - C92 + - Q25 +- Status: '' + LevelAndCategory: '3.5' + Name: one per one + ConversionFactor: 1/1 + Symbol: 1/1 + CommonCode: Q26 + Description: Value of the quotient from two physical units of the same kind as a + numerator and denominator whereas the units are shortened mutually. + conversion: + factor: 1.0 + base_units: + - Q26 +- Status: '' + LevelAndCategory: '3.5' + Name: newton metre per metre + ConversionFactor: m x kg x s⁻² + Symbol: N·m/m² + CommonCode: Q27 + Description: Unit for length-related rotational moment as product of the derived + SI unit newton and the SI base unit metre divided by the SI base unit metre. + conversion: + factor: 1.0 + base_units: + - Q27 +- Status: '' + LevelAndCategory: '3.5' + Name: kilogram per square metre pascal second + ConversionFactor: kg/(m² x Pa x s) + Symbol: kg/(m²·Pa·s) + CommonCode: Q28 + Description: Unit for the ability of a material to allow the transition of steam. + conversion: + factor: 1.0 + base_units: + - Q28 +- Status: '' + LevelAndCategory: 1S + Name: microgram per hectogram + ConversionFactor: 10⁻8 + Symbol: µg/hg + CommonCode: Q29 + Description: Microgram per hectogram. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: pH (potential of Hydrogen) + ConversionFactor: "-log10(mol/l)" + Symbol: pH + CommonCode: Q30 + Description: The activity of the (solvated) hydrogen ion (a logarithmic measure + used to state the acidity or alkalinity of a chemical solution). + conversion: + factor: 1.0 + base_units: + - Q30 +- Status: '' + LevelAndCategory: 1S + Name: kilojoule per gram + ConversionFactor: 10⁶ J/kg + Symbol: kJ/g + CommonCode: Q31 + Description: '' + conversion: + factor: 1000000.0 + base_units: + - J2 +- Status: '' + LevelAndCategory: 1S + Name: femtolitre + ConversionFactor: 10-18 m3 + Symbol: fl + CommonCode: Q32 + Description: '' + conversion: + factor: 1.0e-18 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: picolitre + ConversionFactor: 10-15 m3 + Symbol: pl + CommonCode: Q33 + Description: '' + conversion: + factor: 1.0e-15 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1S + Name: nanolitre + ConversionFactor: 10-12 m3 + Symbol: nl + CommonCode: Q34 + Description: '' + conversion: + factor: 1.0e-12 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: 1M + Name: megawatts per minute + ConversionFactor: 1.667 × 104 W/s + Symbol: MW/min + CommonCode: Q35 + Description: A unit of power defining the total amount of bulk energy transferred + or consumer per minute. + conversion: + factor: 1.0 + base_units: + - Q35 +- Status: '' + LevelAndCategory: '3.1' + Name: square metre per cubic metre + ConversionFactor: 1 m2/m3 + Symbol: m2/m3 + CommonCode: Q36 + Description: A unit of the amount of surface area per unit volume of an object or + collection of objects. + conversion: + factor: 1.0 + base_units: + - Q36 +- Status: "¦" + LevelAndCategory: '2.0' + Name: Standard cubic metre per day + ConversionFactor: 1.15741 × 10-5 m3/s + Symbol: '' + CommonCode: Q37 + Description: Standard cubic metre (temperature 15°C and pressure 1013.25 millibars + ) per day + conversion: + factor: 1.0 + base_units: + - Q37 + - Q39 +- Status: "¦" + LevelAndCategory: '2.0' + Name: Standard cubic metre per hour + ConversionFactor: 2.77778 × 10-4 m3/s + Symbol: '' + CommonCode: Q38 + Description: Standard cubic metre (temperature 15°C and pressure 1013.25 millibars + ) per hour + conversion: + factor: 2.0 + base_units: [] +- Status: "¦" + LevelAndCategory: '2.0' + Name: Normalized cubic metre per day + ConversionFactor: 1.15741 × 10-5 m3/s + Symbol: '' + CommonCode: Q39 + Description: Normalized cubic metre (temperature 0°C and pressure 1013.25 millibars + ) per day + conversion: + factor: 1.0 + base_units: + - Q37 + - Q39 +- Status: "¦" + LevelAndCategory: '2.0' + Name: Normalized cubic metre per hour + ConversionFactor: 2.77778 × 10-4 m3/s + Symbol: '' + CommonCode: Q40 + Description: Normalized cubic metre (temperature 0°C and pressure 1013.25 millibars + ) per hour + conversion: + factor: 2.0 + base_units: [] +- Status: "¦" + LevelAndCategory: '2.0' + Name: Joule per normalised cubic metre + ConversionFactor: '' + Symbol: '' + CommonCode: Q41 + Description: Joule per normalised cubic metre (temperature 0°C and pressure 1013.25 + millibars). + conversion: + factor: 1.0 +- Status: "¦" + LevelAndCategory: '2.0' + Name: Joule per standard cubic metre + ConversionFactor: '' + Symbol: '' + CommonCode: Q42 + Description: Joule per standard cubic metre (temperature 15°C and pressure 1013.25 + millibars). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: meal + ConversionFactor: '' + Symbol: '' + CommonCode: Q3 + Description: 'A unit of count defining the number of meals (meal: an amount of food + to be eaten on a single occasion).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: page - facsimile + ConversionFactor: '' + Symbol: '' + CommonCode: QA + Description: A unit of count defining the number of facsimile pages. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: quarter (of a year) + ConversionFactor: '' + Symbol: '' + CommonCode: QAN + Description: A unit of time defining the number of quarters (3 months). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: page - hardcopy + ConversionFactor: '' + Symbol: '' + CommonCode: QB + Description: 'A unit of count defining the number of hardcopy pages (hardcopy page: + a page rendered as printed or written output on paper, film, or other permanent + medium).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.7' + Name: quarter dozen + ConversionFactor: '3' + Symbol: '' + CommonCode: QD + Description: '' + conversion: + factor: 3.0 +- Status: X + LevelAndCategory: '3.8' + Name: quarter hour + ConversionFactor: 900 s + Symbol: '' + CommonCode: QH + Description: '' + conversion: + factor: 900.0 + base_units: + - H04 + - SEC +- Status: X + LevelAndCategory: '3.8' + Name: quarter kilogram + ConversionFactor: '' + Symbol: '' + CommonCode: QK + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: quire + ConversionFactor: '' + Symbol: qr + CommonCode: QR + Description: 'A unit of count for paper, expressed as the number of quires (quire: + a number of paper sheets, typically 25).' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: quart (US) + ConversionFactor: 0,946 352 9 x 10⁻³ m³ + Symbol: qt (US) + CommonCode: QT + Description: Use liquid quart (common code QTL) + conversion: + factor: 0.0009463529 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: dry quart (US) + ConversionFactor: 1,101 221 x 10⁻³ m³ + Symbol: dry qt (US) + CommonCode: QTD + Description: '' + conversion: + factor: 0.001101221 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: quart (UK) + ConversionFactor: 1,136 522 5 x 10⁻³ m³ + Symbol: qt (UK) + CommonCode: QTI + Description: '' + conversion: + factor: 0.0011365225 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: liquid quart (US) + ConversionFactor: 9,463 529 x 10⁻⁴ m³ + Symbol: liq qt (US) + CommonCode: QTL + Description: '' + conversion: + factor: 0.0009463529 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.5' + Name: quarter (UK) + ConversionFactor: 12,700 59 kg + Symbol: Qr (UK) + CommonCode: QTR + Description: A traditional unit of weight equal to 1/4 hundredweight. In the United + Kingdom, one quarter equals 28 pounds. + conversion: + factor: 12.7 + base_units: [] +- Status: '' + LevelAndCategory: '3.5' + Name: pica + ConversionFactor: 4,217 518 x 10⁻³ m + Symbol: '' + CommonCode: R1 + Description: 'A unit of count defining the number of picas. (pica: typographical + length equal to 12 points or 4.22 mm (approx.)).' + conversion: + factor: 0.004217518 + base_units: + - MTR +- Status: X + LevelAndCategory: '3.5' + Name: calorie + ConversionFactor: 4,186 8 J + Symbol: cal + CommonCode: R4 + Description: Use International Table (IT) calorie (common code D70) + conversion: + factor: 4.1868 + base_units: + - JOU +- Status: '' + LevelAndCategory: '3.8' + Name: thousand cubic metre + ConversionFactor: 10³m³ + Symbol: '' + CommonCode: R9 + Description: A unit of volume equal to one thousand cubic metres. + conversion: + factor: 1000.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.3' + Name: rack + ConversionFactor: '' + Symbol: '' + CommonCode: RA + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: rod + ConversionFactor: '' + Symbol: '' + CommonCode: RD + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: ring + ConversionFactor: '' + Symbol: '' + CommonCode: RG + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: running or operating hour + ConversionFactor: '' + Symbol: '' + CommonCode: RH + Description: A unit of time defining the number of hours of operation. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: roll metric measure + ConversionFactor: '' + Symbol: '' + CommonCode: RK + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: reel + ConversionFactor: '' + Symbol: '' + CommonCode: RL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: ream + ConversionFactor: '' + Symbol: '' + CommonCode: RM + Description: 'A unit of count for paper, expressed as the number of reams (ream: + a large quantity of paper sheets, typically 500).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: ream metric measure + ConversionFactor: '' + Symbol: '' + CommonCode: RN + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: roll + ConversionFactor: '' + Symbol: '' + CommonCode: RO + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: room + ConversionFactor: '' + Symbol: '' + CommonCode: ROM + Description: A unit of count defining the number of rooms. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: pound per ream + ConversionFactor: '' + Symbol: '' + CommonCode: RP + Description: 'A unit of mass for paper, expressed as pounds per ream. (ream: a large + quantity of paper, typically 500 sheets).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: revolutions per minute + ConversionFactor: 1,67 x 10⁻²/s + Symbol: r/min + CommonCode: RPM + Description: Refer ISO/TC12 SI Guide + conversion: + factor: 0.0167 + base_units: + - RPS +- Status: '' + LevelAndCategory: '1' + Name: revolutions per second + ConversionFactor: 1/s + Symbol: r/s + CommonCode: RPS + Description: Refer ISO/TC12 SI Guide + conversion: + factor: 1.0 + base_units: + - RPS +- Status: X + LevelAndCategory: '3.9' + Name: reset + ConversionFactor: '' + Symbol: '' + CommonCode: RS + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: revenue ton mile + ConversionFactor: '' + Symbol: '' + CommonCode: RT + Description: 'A unit of information typically used for billing purposes, expressed + as the number of revenue tons (revenue ton: either a metric ton or a cubic metres, + whichever is the larger), moved over a distance of one mile.' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: run + ConversionFactor: '' + Symbol: '' + CommonCode: RU + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: square foot per second + ConversionFactor: 0,092 903 04 m²/s + Symbol: ft²/s + CommonCode: S3 + Description: 'Synonym: foot squared per second' + conversion: + factor: 0.09290304 + base_units: + - S4 +- Status: '' + LevelAndCategory: '1' + Name: square metre per second + ConversionFactor: m²/s + Symbol: m²/s + CommonCode: S4 + Description: 'Synonym: metre squared per second (square metres/second US)' + conversion: + factor: 1.0 + base_units: + - S4 +- Status: X + LevelAndCategory: '3.8' + Name: sixty fourths of an inch + ConversionFactor: '' + Symbol: '' + CommonCode: S5 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: session + ConversionFactor: '' + Symbol: '' + CommonCode: S6 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: storage unit + ConversionFactor: '' + Symbol: '' + CommonCode: S7 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: standard advertising unit + ConversionFactor: '' + Symbol: '' + CommonCode: S8 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: sack + ConversionFactor: '' + Symbol: '' + CommonCode: SA + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: half year (6 months) + ConversionFactor: '' + Symbol: '' + CommonCode: SAN + Description: A unit of time defining the number of half years (6 months). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: score + ConversionFactor: '20' + Symbol: '' + CommonCode: SCO + Description: A unit of count defining the number of units in multiples of 20. + conversion: + factor: 20.0 +- Status: '' + LevelAndCategory: '3.5' + Name: scruple + ConversionFactor: 1,295 982 g + Symbol: '' + CommonCode: SCR + Description: '' + conversion: + factor: 1.295982 + base_units: [] +- Status: X + LevelAndCategory: '3.1' + Name: solid pound + ConversionFactor: '' + Symbol: '' + CommonCode: SD + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: section + ConversionFactor: '' + Symbol: '' + CommonCode: SE + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: second [unit of time] + ConversionFactor: s + Symbol: s + CommonCode: SEC + Description: '' + conversion: + factor: 1.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.2' + Name: set + ConversionFactor: '' + Symbol: '' + CommonCode: SET + Description: 'A unit of count defining the number of sets (set: a number of objects + grouped together).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: segment + ConversionFactor: '' + Symbol: '' + CommonCode: SG + Description: A unit of information equal to 64000 bytes. + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '3.4' + Name: shipping ton + ConversionFactor: '' + Symbol: '' + CommonCode: SHT + Description: A unit of mass defining the number of tons for shipping. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: siemens + ConversionFactor: A/V + Symbol: S + CommonCode: SIE + Description: '' + conversion: + factor: 1.0 + base_units: + - SIE +- Status: X + LevelAndCategory: '3.4' + Name: split tank truck + ConversionFactor: '' + Symbol: '' + CommonCode: SK + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: slipsheet + ConversionFactor: '' + Symbol: '' + CommonCode: SL + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: "¦" + LevelAndCategory: '2' + Name: Standard cubic metre + ConversionFactor: m3 + Symbol: '' + CommonCode: SM3 + Description: Standard cubic metre (temperature 15°C and pressure 1013.25 millibars + ) + conversion: + factor: 1.0 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '2' + Name: mile (statute mile) + ConversionFactor: 1 609,344 m + Symbol: mile + CommonCode: SMI + Description: '' + conversion: + factor: 1609.344 + base_units: + - MTR +- Status: X + LevelAndCategory: '3.8' + Name: square rod + ConversionFactor: 25,292 9 m² + Symbol: rd² + CommonCode: SN + Description: '' + conversion: + factor: 25.2929 + base_units: + - MTK +- Status: X + LevelAndCategory: '3.3' + Name: spool + ConversionFactor: '' + Symbol: '' + CommonCode: SO + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: shelf package + ConversionFactor: '' + Symbol: '' + CommonCode: SP + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: square + ConversionFactor: '' + Symbol: '' + CommonCode: SQ + Description: 'A unit of count defining the number of squares (square: rectangular + shape).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: square, roofing + ConversionFactor: '' + Symbol: '' + CommonCode: SQR + Description: A unit of count defining the number of squares of roofing materials, + measured in multiples of 100 square feet. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: strip + ConversionFactor: '' + Symbol: '' + CommonCode: SR + Description: 'A unit of count defining the number of strips (strip: long narrow + piece of an object).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: sheet metric measure + ConversionFactor: '' + Symbol: '' + CommonCode: SS + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: short standard (7200 matches) + ConversionFactor: '' + Symbol: '' + CommonCode: SST + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: sheet + ConversionFactor: '' + Symbol: '' + CommonCode: ST + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: stick + ConversionFactor: '' + Symbol: '' + CommonCode: STC + Description: 'A unit of count defining the number of sticks (stick: slender and + often cylindrical piece of a substance).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: stone (UK) + ConversionFactor: 6,350 293 kg + Symbol: st + CommonCode: STI + Description: '' + conversion: + factor: 6.350293 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.9' + Name: stick, cigarette + ConversionFactor: '' + Symbol: '' + CommonCode: STK + Description: A unit of count defining the number of cigarettes in the smallest unit + for stock-taking and/or duty computation. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: standard litre + ConversionFactor: '' + Symbol: '' + CommonCode: STL + Description: A unit of volume defining the number of litres of a product at a temperature + of 15 degrees Celsius, especially in relation to hydrocarbon oils. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: ton (US) or short ton (UK/US) + ConversionFactor: 0,907184 7 x 10³ kg + Symbol: ton (US) + CommonCode: STN + Description: 'Synonym: net ton (2000 lb)' + conversion: + factor: 907.1847 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.9' + Name: straw + ConversionFactor: '' + Symbol: '' + CommonCode: STW + Description: 'A unit of count defining the number of straws (straw: a slender tube + used for sucking up liquids).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: skid + ConversionFactor: '' + Symbol: '' + CommonCode: SV + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: skein + ConversionFactor: '' + Symbol: '' + CommonCode: SW + Description: 'A unit of count defining the number of skeins (skein: a loosely-coiled + bundle of yarn or thread).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: shipment + ConversionFactor: '' + Symbol: '' + CommonCode: SX + Description: 'A unit of count defining the number of shipments (shipment: an amount + of goods shipped or transported).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: syringe + ConversionFactor: '' + Symbol: '' + CommonCode: SYR + Description: 'A unit of count defining the number of syringes (syringe: a small + device for pumping, spraying and/or injecting liquids through a small aperture).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: telecommunication line in service + ConversionFactor: '' + Symbol: '' + CommonCode: T0 + Description: A unit of count defining the number of lines in service. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand pound gross + ConversionFactor: '' + Symbol: '' + CommonCode: T1 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: thousand piece + ConversionFactor: '' + Symbol: '' + CommonCode: T3 + Description: 'A unit of count defining the number of pieces in multiples of 1000 + (piece: a single item, article or exemplar).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand bag + ConversionFactor: '' + Symbol: '' + CommonCode: T4 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand casing + ConversionFactor: '' + Symbol: '' + CommonCode: T5 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand gallon (US) + ConversionFactor: 3,785 412 m³ + Symbol: '' + CommonCode: T6 + Description: '' + conversion: + factor: 3.785412 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.8' + Name: thousand impression + ConversionFactor: '' + Symbol: '' + CommonCode: T7 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand linear inch + ConversionFactor: '' + Symbol: '' + CommonCode: T8 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: tenth cubic foot + ConversionFactor: '' + Symbol: '' + CommonCode: TA + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1M + Name: kiloampere hour (thousand ampere hour) + ConversionFactor: 3,6 x 10⁶ C + Symbol: kA·h + CommonCode: TAH + Description: '' + conversion: + factor: 3600000.0 + base_units: + - A8 +- Status: '' + LevelAndCategory: '3.5' + Name: total acid number + ConversionFactor: 'mg KOH/g ' + Symbol: '' + CommonCode: TAN + Description: A unit of chemistry defining the amount of potassium hydroxide (KOH) + in milligrams that is needed to neutralize the acids in one gram of oil. It is + an important quality measurement of crude oil. + conversion: + factor: 1.0 + base_units: + - TAN +- Status: X + LevelAndCategory: '3.4' + Name: truckload + ConversionFactor: '' + Symbol: '' + CommonCode: TC + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: therm + ConversionFactor: 10⁵ x 1 055,056 J + Symbol: '' + CommonCode: TD + Description: '' + conversion: + factor: 100000.0 + base_units: [] +- Status: X + LevelAndCategory: '3.3' + Name: tote + ConversionFactor: '' + Symbol: '' + CommonCode: TE + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: ten square yard + ConversionFactor: '' + Symbol: '' + CommonCode: TF + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: thousand square inch + ConversionFactor: '' + Symbol: '' + CommonCode: TI + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: metric ton, including container + ConversionFactor: '' + Symbol: '' + CommonCode: TIC + Description: A unit of mass defining the number of metric tons of a product, including + its container. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: metric ton, including inner packaging + ConversionFactor: '' + Symbol: '' + CommonCode: TIP + Description: A unit of mass defining the number of metric tons of a product, including + its inner packaging materials. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand square centimetre + ConversionFactor: '' + Symbol: '' + CommonCode: TJ + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: tank, rectangular + ConversionFactor: '' + Symbol: '' + CommonCode: TK + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.4' + Name: tonne kilometre + ConversionFactor: 10⁶ kg x m + Symbol: t·km + CommonCode: TKM + Description: 'A unit of information typically used for billing purposes, expressed + as the number of tonnes (metric tons) moved over a distance of one kilometre. ' + conversion: + factor: 1000000.0 + base_units: + - M94 +- Status: X + LevelAndCategory: '3.8' + Name: thousand foot (linear) + ConversionFactor: '' + Symbol: '' + CommonCode: TL + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: kilogram of imported meat, less offal + ConversionFactor: '' + Symbol: '' + CommonCode: TMS + Description: A unit of mass equal to one thousand grams of imported meat, disregarding + less valuable by-products such as the entrails. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: tin + ConversionFactor: '' + Symbol: '' + CommonCode: TN + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: 1S + Name: tonne (metric ton) + ConversionFactor: 10³ kg + Symbol: t + CommonCode: TNE + Description: 'Synonym: metric ton' + conversion: + factor: 1000.0 + base_units: + - KGM +- Status: '' + LevelAndCategory: '3.2' + Name: ten pack + ConversionFactor: '' + Symbol: '' + CommonCode: TP + Description: A unit of count defining the number of items in multiples of 10. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: teeth per inch + ConversionFactor: 0.0254 /m + Symbol: '' + CommonCode: TPI + Description: The number of teeth per inch. + conversion: + factor: 0.0 + base_units: [] +- Status: '' + LevelAndCategory: '3.8' + Name: ten pair + ConversionFactor: '' + Symbol: '' + CommonCode: TPR + Description: 'A unit of count defining the number of pairs in multiples of 10 (pair: + item described by two''s).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand foot + ConversionFactor: '' + Symbol: '' + CommonCode: TQ + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.8' + Name: thousand cubic metre per day + ConversionFactor: 1,157 41 x 10⁻² m³/s + Symbol: km³/d + CommonCode: TQD + Description: A unit of volume equal to one thousand cubic metres per day. + conversion: + factor: 0.0115741 + base_units: + - MQS +- Status: X + LevelAndCategory: '3.8' + Name: ten square foot + ConversionFactor: '' + Symbol: '' + CommonCode: TR + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.7' + Name: trillion (EUR) + ConversionFactor: 10¹⁸ + Symbol: '' + CommonCode: TRL + Description: '' + conversion: + factor: 1.0e+18 +- Status: X + LevelAndCategory: '3.8' + Name: thousand square foot + ConversionFactor: '' + Symbol: '' + CommonCode: TS + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: tonne of substance 90 % dry + ConversionFactor: '' + Symbol: '' + CommonCode: TSD + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.1' + Name: ton of steam per hour + ConversionFactor: '' + Symbol: '' + CommonCode: TSH + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: ten set + ConversionFactor: '' + Symbol: '' + CommonCode: TST + Description: 'A unit of count defining the number of sets in multiples of 10 (set: + a number of objects grouped together).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand linear metre + ConversionFactor: '' + Symbol: '' + CommonCode: TT + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: ten thousand sticks + ConversionFactor: '' + Symbol: '' + CommonCode: TTS + Description: 'A unit of count defining the number of sticks in multiples of 10000 + (stick: slender and often cylindrical piece of a substance).' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: tube + ConversionFactor: '' + Symbol: '' + CommonCode: TU + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: thousand kilogram + ConversionFactor: 10³kg + Symbol: '' + CommonCode: TV + Description: '' + conversion: + factor: 1000.0 + base_units: + - KGM +- Status: X + LevelAndCategory: '3.8' + Name: thousand sheet + ConversionFactor: '' + Symbol: '' + CommonCode: TW + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: tank, cylindrical + ConversionFactor: '' + Symbol: '' + CommonCode: TY + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: treatment + ConversionFactor: '' + Symbol: '' + CommonCode: U1 + Description: 'A unit of count defining the number of treatments (treatment: subjection + to the action of a chemical, physical or biological agent).' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: tablet + ConversionFactor: '' + Symbol: '' + CommonCode: U2 + Description: 'A unit of count defining the number of tablets (tablet: a small flat + or compressed solid object).' + conversion: + factor: 1.0 +- Status: D + LevelAndCategory: '2' + Name: torr + ConversionFactor: 133,322 4 Pa + Symbol: Torr + CommonCode: UA + Description: '' + conversion: + factor: 133.3224 + base_units: + - C55 + - PAL +- Status: '' + LevelAndCategory: '3.5' + Name: telecommunication line in service average + ConversionFactor: '' + Symbol: '' + CommonCode: UB + Description: A unit of count defining the average number of lines in service. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: telecommunication port + ConversionFactor: '' + Symbol: '' + CommonCode: UC + Description: A unit of count defining the number of network access ports. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: tenth minute + ConversionFactor: 6 s + Symbol: '' + CommonCode: UD + Description: '' + conversion: + factor: 6.0 + base_units: + - H04 + - SEC +- Status: X + LevelAndCategory: '3.8' + Name: tenth hour + ConversionFactor: 360 s + Symbol: '' + CommonCode: UE + Description: '' + conversion: + factor: 360.0 + base_units: + - H04 + - SEC +- Status: X + LevelAndCategory: '3.5' + Name: usage per telecommunication line average + ConversionFactor: '' + Symbol: '' + CommonCode: UF + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: ten thousand yard + ConversionFactor: '' + Symbol: '' + CommonCode: UH + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: million unit + ConversionFactor: '' + Symbol: '' + CommonCode: UM + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: volt - ampere per kilogram + ConversionFactor: V x A / kg + Symbol: V·A / kg + CommonCode: VA + Description: '' + conversion: + factor: 1.0 + base_units: + - VA +- Status: X + LevelAndCategory: '3.3' + Name: vial + ConversionFactor: '' + Symbol: '' + CommonCode: VI + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: volt + ConversionFactor: V + Symbol: V + CommonCode: VLT + Description: '' + conversion: + factor: 1.0 + base_units: + - 2G + - 2H + - VLT +- Status: '' + LevelAndCategory: '3.7' + Name: percent volume + ConversionFactor: '' + Symbol: '' + CommonCode: VP + Description: A measure of concentration, typically expressed as the percentage volume + of a solute in a solution. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: bulk + ConversionFactor: '' + Symbol: '' + CommonCode: VQ + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: visit + ConversionFactor: '' + Symbol: '' + CommonCode: VS + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: wet kilo + ConversionFactor: '' + Symbol: '' + CommonCode: W2 + Description: A unit of mass defining the number of kilograms of a product, including + the water content of the product. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.8' + Name: two week + ConversionFactor: '' + Symbol: '' + CommonCode: W4 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: watt per kilogram + ConversionFactor: 1 W/kg + Symbol: W/kg + CommonCode: WA + Description: '' + conversion: + factor: 1.0 + base_units: + - WA +- Status: '' + LevelAndCategory: '3.1' + Name: wet pound + ConversionFactor: '' + Symbol: '' + CommonCode: WB + Description: A unit of mass defining the number of pounds of a material, including + the water content of the material. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: cord + ConversionFactor: 3,63 m³ + Symbol: '' + CommonCode: WCD + Description: A unit of volume used for measuring lumber. One board foot equals 1/12 + of a cubic foot. + conversion: + factor: 3.63 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '3.1' + Name: wet ton + ConversionFactor: '' + Symbol: '' + CommonCode: WE + Description: A unit of mass defining the number of tons of a material, including + the water content of the material. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: weber + ConversionFactor: Wb + Symbol: Wb + CommonCode: WEB + Description: '' + conversion: + factor: 1.0 + base_units: + - WEB +- Status: '' + LevelAndCategory: '2' + Name: week + ConversionFactor: 6,048 x 10⁵ s + Symbol: wk + CommonCode: WEE + Description: '' + conversion: + factor: 604800.0 + base_units: + - H04 + - SEC +- Status: '' + LevelAndCategory: '3.1' + Name: wine gallon + ConversionFactor: '' + Symbol: '' + CommonCode: WG + Description: A unit of volume equal to 231 cubic inches. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: wheel + ConversionFactor: '' + Symbol: '' + CommonCode: WH + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '1' + Name: watt hour + ConversionFactor: 3,6 x 10³ J + Symbol: W·h + CommonCode: WHR + Description: '' + conversion: + factor: 3600.0 + base_units: + - JOU +- Status: X + LevelAndCategory: '3.9' + Name: weight per square inch + ConversionFactor: '' + Symbol: '' + CommonCode: WI + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.1' + Name: working month + ConversionFactor: '' + Symbol: '' + CommonCode: WM + Description: A unit of time defining the number of working months. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: wrap + ConversionFactor: '' + Symbol: '' + CommonCode: WR + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: standard + ConversionFactor: 4,672 m³ + Symbol: std + CommonCode: WSD + Description: 'A unit of volume of finished lumber equal to 165 cubic feet.,Synonym: + standard cubic foot' + conversion: + factor: 4.672 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: '' + LevelAndCategory: '1' + Name: watt + ConversionFactor: W + Symbol: W + CommonCode: WTT + Description: '' + conversion: + factor: 1.0 + base_units: + - D46 + - P14 + - WTT +- Status: D + LevelAndCategory: '3.1' + Name: millilitre of water + ConversionFactor: '' + Symbol: '' + CommonCode: WW + Description: A unit of volume equal to the number of millilitres of water. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: Gunter's chain + ConversionFactor: 20,116 8 m + Symbol: ch (UK) + CommonCode: X1 + Description: A unit of distance used or formerly used by British surveyors. + conversion: + factor: 20.1168 + base_units: + - MTR +- Status: '' + LevelAndCategory: '2' + Name: square yard + ConversionFactor: 8,361 274 x 10⁻¹ m² + Symbol: yd² + CommonCode: YDK + Description: '' + conversion: + factor: 0.8361274 + base_units: + - MTK +- Status: '' + LevelAndCategory: '2' + Name: cubic yard + ConversionFactor: 0,764 555 m³ + Symbol: yd³ + CommonCode: YDQ + Description: '' + conversion: + factor: 0.764555 + base_units: + - D40 + - G26 + - K6 + - MTQ + - NM3 + - SM3 +- Status: X + LevelAndCategory: '3.8' + Name: hundred linear yard + ConversionFactor: '' + Symbol: '' + CommonCode: YL + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '2' + Name: yard + ConversionFactor: 0,914 4 m + Symbol: yd + CommonCode: YRD + Description: '' + conversion: + factor: 0.9144 + base_units: + - MTR +- Status: X + LevelAndCategory: '3.8' + Name: ten yard + ConversionFactor: '' + Symbol: '' + CommonCode: YT + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.4' + Name: lift van + ConversionFactor: '' + Symbol: '' + CommonCode: Z1 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: hanging container + ConversionFactor: '' + Symbol: '' + CommonCode: Z11 + Description: A unit of count defining the number of hanging containers. + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: chest + ConversionFactor: '' + Symbol: '' + CommonCode: Z2 + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: cask + ConversionFactor: '' + Symbol: '' + CommonCode: Z3 + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.3' + Name: hogshead + ConversionFactor: '' + Symbol: '' + CommonCode: Z4 + Description: Use UN/ECE Recommendation 21 (refer to Note 2 in the spreadsheet introduction, + 1st sheet). + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: lug + ConversionFactor: '' + Symbol: '' + CommonCode: Z5 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.5' + Name: conference point + ConversionFactor: '' + Symbol: '' + CommonCode: Z6 + Description: '' + conversion: + factor: 1.0 +- Status: X + LevelAndCategory: '3.9' + Name: newspage agate line + ConversionFactor: '' + Symbol: '' + CommonCode: Z8 + Description: '' + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.5' + Name: page + ConversionFactor: '' + Symbol: '' + CommonCode: ZP + Description: A unit of count defining the number of pages. + conversion: + factor: 1.0 +- Status: '' + LevelAndCategory: '3.9' + Name: mutually defined + ConversionFactor: '' + Symbol: '' + CommonCode: ZZ + Description: A unit of measure as agreed in common between two or more parties. + conversion: + factor: 1.0 diff --git a/config/units-of-measure/un-ece-20.yml b/config/units-of-measure/un-ece-20.yml new file mode 100644 index 000000000..71695a964 --- /dev/null +++ b/config/units-of-measure/un-ece-20.yml @@ -0,0 +1,15383 @@ +# downloaded json from https://github.com/datasets/unece-units-of-measure and manually converted to yaml using +# `ruby -ryaml -rjson -e 'puts YAML.dump(JSON.parse(STDIN.read))' 10 kpa +- Code: WH + Description: + Name: Intermediate bulk container, aluminium, pressurised > 10 kpa +- Code: WJ + Description: + Name: Intermediate bulk container, metal, pressure 10 kpa +- Code: WK + Description: + Name: Intermediate bulk container, steel, liquid +- Code: WL + Description: + Name: Intermediate bulk container, aluminium, liquid +- Code: WM + Description: + Name: Intermediate bulk container, metal, liquid +- Code: WN + Description: + Name: Intermediate bulk container, woven plastic, without coat/liner +- Code: WP + Description: + Name: Intermediate bulk container, woven plastic, coated +- Code: WQ + Description: + Name: Intermediate bulk container, woven plastic, with liner +- Code: WR + Description: + Name: Intermediate bulk container, woven plastic, coated and liner +- Code: WS + Description: + Name: Intermediate bulk container, plastic film +- Code: WT + Description: + Name: Intermediate bulk container, textile with out coat/liner +- Code: WU + Description: + Name: Intermediate bulk container, natural wood, with inner liner +- Code: WV + Description: + Name: Intermediate bulk container, textile, coated +- Code: WW + Description: + Name: Intermediate bulk container, textile, with liner +- Code: WX + Description: + Name: Intermediate bulk container, textile, coated and liner +- Code: WY + Description: + Name: Intermediate bulk container, plywood, with inner liner +- Code: WZ + Description: + Name: Intermediate bulk container, reconstituted wood, with inner liner +- Code: XA + Description: + Name: Bag, woven plastic, without inner coat/liner +- Code: XB + Description: + Name: Bag, woven plastic, sift proof +- Code: XC + Description: + Name: Bag, woven plastic, water resistant +- Code: XD + Description: + Name: Bag, plastics film +- Code: XF + Description: + Name: Bag, textile, without inner coat/liner +- Code: XG + Description: + Name: Bag, textile, sift proof +- Code: XH + Description: + Name: Bag, textile, water resistant +- Code: XJ + Description: + Name: Bag, paper, multi-wall +- Code: XK + Description: + Name: Bag, paper, multi-wall, water resistant +- Code: YA + Description: + Name: Composite packaging, plastic receptacle in steel drum +- Code: YB + Description: + Name: Composite packaging, plastic receptacle in steel crate box +- Code: YC + Description: + Name: Composite packaging, plastic receptacle in aluminium drum +- Code: YD + Description: + Name: Composite packaging, plastic receptacle in aluminium crate +- Code: YF + Description: + Name: Composite packaging, plastic receptacle in wooden box +- Code: YG + Description: + Name: Composite packaging, plastic receptacle in plywood drum +- Code: YH + Description: + Name: Composite packaging, plastic receptacle in plywood box +- Code: YJ + Description: + Name: Composite packaging, plastic receptacle in fibre drum +- Code: YK + Description: + Name: Composite packaging, plastic receptacle in fibreboard box +- Code: YL + Description: + Name: Composite packaging, plastic receptacle in plastic drum +- Code: YM + Description: + Name: Composite packaging, plastic receptacle in solid plastic box +- Code: YN + Description: + Name: Composite packaging, glass receptacle in steel drum +- Code: YP + Description: + Name: Composite packaging, glass receptacle in steel crate box +- Code: YQ + Description: + Name: Composite packaging, glass receptacle in aluminium drum +- Code: YR + Description: + Name: Composite packaging, glass receptacle in aluminium crate +- Code: YS + Description: + Name: Composite packaging, glass receptacle in wooden box +- Code: YT + Description: + Name: Composite packaging, glass receptacle in plywood drum +- Code: YV + Description: + Name: Composite packaging, glass receptacle in wickerwork hamper +- Code: YW + Description: + Name: Composite packaging, glass receptacle in fibre drum +- Code: YX + Description: + Name: Composite packaging, glass receptacle in fibreboard box +- Code: YY + Description: + Name: Composite packaging, glass receptacle in expandable plastic pack +- Code: YZ + Description: + Name: Composite packaging, glass receptacle in solid plastic pack +- Code: ZA + Description: + Name: Intermediate bulk container, paper, multi-wall +- Code: ZB + Description: + Name: Bag, large +- Code: ZC + Description: + Name: Intermediate bulk container, paper, multi-wall, water resistant +- Code: ZD + Description: + Name: Intermediate bulk container, rigid plastic, with structural equipment, solids +- Code: ZF + Description: + Name: Intermediate bulk container, rigid plastic, freestanding, solids +- Code: ZG + Description: + Name: Intermediate bulk container, rigid plastic, with structural equipment, pressurised +- Code: ZH + Description: + Name: Intermediate bulk container, rigid plastic, freestanding, pressurised +- Code: ZJ + Description: + Name: Intermediate bulk container, rigid plastic, with structural equipment, liquids +- Code: ZK + Description: + Name: Intermediate bulk container, rigid plastic, freestanding, liquids +- Code: ZL + Description: + Name: Intermediate bulk container, composite, rigid plastic, solids +- Code: ZM + Description: + Name: Intermediate bulk container, composite, flexible plastic, solids +- Code: ZN + Description: + Name: Intermediate bulk container, composite, rigid plastic, pressurised +- Code: ZP + Description: + Name: Intermediate bulk container, composite, flexible plastic, pressurised +- Code: ZQ + Description: + Name: Intermediate bulk container, composite, rigid plastic, liquids +- Code: ZR + Description: + Name: Intermediate bulk container, composite, flexible plastic, liquids +- Code: ZS + Description: + Name: Intermediate bulk container, composite +- Code: ZT + Description: + Name: Intermediate bulk container, fibreboard +- Code: ZU + Description: + Name: Intermediate bulk container, flexible +- Code: ZV + Description: + Name: Intermediate bulk container, metal, other than steel +- Code: ZW + Description: + Name: Intermediate bulk container, natural wood +- Code: ZX + Description: + Name: Intermediate bulk container, plywood +- Code: ZY + Description: + Name: Intermediate bulk container, reconstituted wood +- Code: ZZ + Description: + Name: Mutually defined +- Code: '13' + Description: + Name: Flexible IBC for solids, filled or discharged by gravity (liquids and solids + under pressure [>0.1 bar] are not permitted) +- Code: 13H1 + Description: + Name: Woven PP fabric without coating or inner liner +- Code: 13H2 + Description: + Name: Woven PP fabric, coated +- Code: 13H3 + Description: + Name: Woven PP fabric with inner liner +- Code: 13H4 + Description: + Name: Woven PP fabric, coated and with inner liner diff --git a/db/migrate/20240726083740_alter_articles_add_versioning.rb b/db/migrate/20240726083740_alter_articles_add_versioning.rb new file mode 100644 index 000000000..7914c8cd9 --- /dev/null +++ b/db/migrate/20240726083740_alter_articles_add_versioning.rb @@ -0,0 +1,217 @@ +class AlterArticlesAddVersioning < ActiveRecord::Migration[5.2] + def up + rename_table :article_prices, :article_versions + rename_column :order_articles, :article_price_id, :article_version_id + + change_table :article_versions do |t| + t.string :name, default: '', null: false + t.integer :article_category_id, default: 0, null: false + t.string :unit, default: '' + t.string :note + t.boolean :availability, default: true, null: false + t.string :manufacturer + t.string :origin + t.string :order_number + t.datetime :updated_at + end + + # copy all article fields into article_versions + articles = select_all('SELECT article_versions.id AS article_version_id, articles.* FROM article_versions JOIN articles ON articles.id = article_versions.article_id') + articles.each do |article| + update(%( + UPDATE article_versions SET + name = #{quote article['name']}, + article_category_id = #{quote article['article_category_id']}, + unit = #{quote article['unit']}, + note = #{quote article['note']}, + availability = #{quote article['availability']}, + manufacturer = #{quote article['manufacturer']}, + origin = #{quote article['origin']}, + order_number = #{quote article['order_number']}, + updated_at = #{quote article['updated_at']} + WHERE id = #{quote article['article_version_id']} + )) + end + + remove_index :articles, %i[name supplier_id] + + # drop article columns (now superfluous as they exist in article_versions): + change_table :articles do |t| + t.remove :name + t.remove :article_category_id + t.remove :unit + t.remove :note + t.remove :availability + t.remove :manufacturer + t.remove :origin + t.remove :order_number + t.remove :updated_at + t.remove :price + t.remove :tax + t.remove :deposit + t.remove :unit_quantity + end + + # remove order_articles' reference to articles (reference now always goes through article_versions): + articles = select_all(%( + SELECT articles.id AS article_id, article_versions.id AS article_version_id + FROM articles + JOIN article_versions ON article_versions.article_id = articles.id + JOIN order_articles ON order_articles.article_id = articles.id + WHERE order_articles.article_version_id IS NULL + GROUP BY article_versions.article_id + ORDER BY article_versions.created_at DESC + )) + + articles.each do |article| + update(%( + UPDATE order_articles + SET article_version_id = #{quote article['article_version_id']} + WHERE order_articles.article_version_id IS NULL + AND order_articles.article_id = #{quote article['article_id']} + )) + end + + # Remove orphaned order articles (db inconsistencies due to lack of foreign key constraints): + delete('DELETE FROM order_articles WHERE order_articles.article_version_id IS NULL') + + # De-duplicate article version (db inconsistencies due to lack of unique key for created_at and article_id): + duplicate_article_versions = select_all(%{ + SELECT article_id, created_at + FROM article_versions + GROUP BY article_id, created_at + HAVING COUNT(*) > 1 + }) + + duplicate_article_versions.each do |duplicate_article_version| + article_versions = select_all(%( + SELECT id + FROM article_versions + WHERE article_id = #{quote duplicate_article_version['article_id']} + AND created_at = #{quote duplicate_article_version['created_at']} + )) + + latest_version = article_versions.last + article_versions[0..-2].each do |obsolete_version| + update("UPDATE order_articles SET article_version_id = #{quote latest_version['id']} WHERE article_version_id = #{quote obsolete_version['id']}") + delete("DELETE FROM article_versions WHERE id = #{quote obsolete_version['id']}") + end + end + + remove_index :order_articles, %i[order_id article_id] + remove_column :order_articles, :article_id + change_column_null :order_articles, :article_version_id, false + add_index :order_articles, %i[order_id article_version_id], unique: true + add_index :order_articles, :article_version_id + remove_index :article_versions, :article_id + add_index :article_versions, %i[article_id created_at], unique: true + add_index :article_versions, [:article_category_id] + end + + def down + rename_table :article_versions, :article_prices + rename_column :order_articles, :article_version_id, :article_price_id + + remove_index :order_articles, %i[order_id article_price_id] + remove_index :order_articles, :article_price_id + remove_index :article_prices, %i[article_id created_at] + remove_index :article_prices, [:article_category_id] + + add_column :order_articles, :article_id, :integer + change_column_null :order_articles, :article_price_id, true + + change_table :articles do |t| + t.string :name, default: '', null: false + t.integer :article_category_id, default: 0, null: false + t.string :unit, default: '' + t.string :note + t.boolean :availability, default: true, null: false + t.string :manufacturer + t.string :origin + t.string :order_number + t.datetime :updated_at + t.decimal :price, precision: 8, scale: 2 + t.float :tax + t.decimal :deposit, precision: 8, scale: 2, default: '0.0' + t.integer :unit_quantity, null: false, default: 0 + end + + article_prices = select_all(%{ + SELECT article_prices.* + FROM article_prices + JOIN ( + SELECT article_id, MAX(created_at) AS max_created_at + FROM article_prices + GROUP BY article_id + ) AS latest_article_prices + ON latest_article_prices.article_id = article_prices.article_id + AND latest_article_prices.max_created_at = article_prices.created_at + }) + article_prices.each do |article_price| + update(%( + UPDATE articles SET + name = #{quote article_price['name']}, + article_category_id = #{quote article_price['article_category_id']}, + unit = #{quote article_price['unit']}, + note = #{quote article_price['note']}, + availability = #{quote article_price['availability']}, + manufacturer = #{quote article_price['manufacturer']}, + origin = #{quote article_price['origin']}, + order_number = #{quote article_price['order_number']}, + updated_at = #{quote article_price['updated_at']}, + type = #{quote article_price['type']}, + price = #{quote article_price['price']}, + tax = #{quote article_price['tax']}, + deposit = #{quote article_price['deposit']}, + unit_quantity = #{quote article_price['unit_quantity']} + WHERE id = #{quote article_price['article_id']} + )) + end + + order_articles = select_all(%( + SELECT order_articles.id, article_prices.article_id + FROM order_articles + JOIN article_prices ON article_prices.id = order_articles.article_price_id + )) + + order_articles.each do |order_article| + update(%( + UPDATE order_articles + SET article_id = #{quote order_article['article_id']} + WHERE id = #{quote order_article['id']} + )) + end + + update(%{ + UPDATE order_articles + SET article_price_id = NULL + WHERE order_id IN (SELECT id FROM orders WHERE state = #{quote 'open'}) + }) + + change_table :article_prices do |t| + t.remove :name + t.remove :article_category_id + t.remove :unit + t.remove :note + t.remove :availability + t.remove :manufacturer + t.remove :origin + t.remove :order_number + t.remove :updated_at + end + + change_column_default :articles, :unit_quantity, nil + change_column_null :order_articles, :article_id, false + add_index :order_articles, %i[order_id article_id], unique: true + add_index :article_prices, :article_id + add_index :articles, %i[name supplier_id] + end + + protected + + # We cannot use quote out of context (as it wouldn't relate to the current DB syntax), + # but using Article's db connection by default should be fine + def quote(value) + Article.connection.quote(value) + end +end diff --git a/db/migrate/20240726083741_alter_articles_add_more_unit_logic.rb b/db/migrate/20240726083741_alter_articles_add_more_unit_logic.rb new file mode 100644 index 000000000..2aa8100c5 --- /dev/null +++ b/db/migrate/20240726083741_alter_articles_add_more_unit_logic.rb @@ -0,0 +1,112 @@ +class AlterArticlesAddMoreUnitLogic < ActiveRecord::Migration[5.2] + def up + change_table :article_versions do |t| + t.column :supplier_order_unit, :string, length: 3 + t.column :price_unit, :string, length: 3 + t.column :billing_unit, :string, length: 3 + t.column :group_order_unit, :string, length: 3 + t.column :group_order_granularity, :decimal, precision: 8, scale: 3, null: false, default: 1 + t.column :minimum_order_quantity, :float + t.change :price, :decimal, precision: 11, scale: 6, null: false, comment: 'stored in `article_versions.supplier_order_unit`' + t.change :unit, :string, null: true, default: nil + end + + create_table :article_unit_ratios do |t| + t.references :article_version, null: false + + t.column :sort, :integer, null: false, index: true + t.column :quantity, :decimal, precision: 38, scale: 3, null: false + t.column :unit, :string, length: 3 + end + + article_versions = select_all('SELECT id, unit, unit_quantity, price FROM article_versions WHERE unit_quantity > 1 AND NOT unit IS NULL') + article_versions.each do |article_version| + insert(%{ + INSERT INTO article_unit_ratios (article_version_id, sort, quantity, unit) + VALUES ( + #{quote article_version['id']}, + #{quote 1}, + #{quote article_version['unit_quantity']}, + #{quote 'XPP'} + ) + }) + + compound_unit = "#{article_version['unit_quantity']}x#{article_version['unit']}" + update(%( + UPDATE article_versions + SET unit = #{quote compound_unit}, + group_order_granularity = #{quote 1}, + group_order_unit = #{quote 'XPP'}, + price = #{quote article_version['price'].to_f * article_version['unit_quantity']}, + price_unit = #{quote 'XPP'}, + billing_unit = #{quote 'XPP'} + WHERE article_versions.id = #{quote article_version['id']} + )) + end + + change_table :article_versions do |t| + t.remove :unit_quantity + end + + change_table :order_articles do |t| + t.change :quantity, :decimal, precision: 8, scale: 3, null: false, comment: 'stored in `article_versions.group_order_unit`' + t.change :tolerance, :decimal, precision: 8, scale: 3, null: false, comment: 'stored in `article_versions.group_order_unit`' + t.change :units_to_order, :decimal, precision: 11, scale: 6, null: false, comment: 'stored in `article_versions.supplier_order_unit`' + t.change :units_billed, :decimal, precision: 11, scale: 6, null: true, comment: 'stored in `article_versions.supplier_order_unit`' + t.change :units_received, :decimal, precision: 11, scale: 6, null: true, comment: 'stored in `article_versions.supplier_order_unit`' + end + + change_table :group_order_articles do |t| + t.change :quantity, :decimal, precision: 8, scale: 3, null: false + t.change :tolerance, :decimal, precision: 8, scale: 3, null: false + end + + change_table :group_order_article_quantities do |t| + t.change :quantity, :decimal, precision: 8, scale: 3, null: false + t.change :tolerance, :decimal, precision: 8, scale: 3, null: false + end + end + + def down + change_table :article_versions do |t| + t.remove :supplier_order_unit + t.remove :price_unit + t.remove :billing_unit + t.remove :group_order_unit + t.remove :group_order_granularity + t.remove :minimum_order_quantity + t.column :unit_quantity, :integer, null: false + t.change :price, :decimal, precision: 8, scale: 2, null: false, comment: '' + t.change :unit, :string, null: true, default: '' + end + + article_unit_ratios = select_all('SELECT article_version_id, quantity FROM article_unit_ratios WHERE sort=1') + article_unit_ratios.each do |article_unit_ratio| + update(%( + UPDATE article_versions + SET unit_quantity = #{quote article_unit_ratio['quantity']} + WHERE id = #{quote article_unit_ratio['article_version_id']} + )) + end + + drop_table :article_unit_ratios + + change_table :order_articles do |t| + t.change :quantity, :integer, null: false, comment: nil + t.change :tolerance, :integer, null: false, comment: nil + t.change :units_to_order, :integer, null: false, comment: nil + t.change :units_billed, :decimal, precision: 8, scale: 3, null: true, comment: nil + t.change :units_received, :decimal, precision: 8, scale: 3, null: true, comment: nil + end + + change_table :group_order_articles do |t| + t.change :quantity, :integer, null: false + t.change :tolerance, :integer, null: false + end + + change_table :group_order_article_quantities do |t| + t.change :quantity, :integer, null: false + t.change :tolerance, :integer, null: false + end + end +end diff --git a/db/migrate/20240726083742_alter_suppliers_sharing_fields.rb b/db/migrate/20240726083742_alter_suppliers_sharing_fields.rb new file mode 100644 index 000000000..5d66df18d --- /dev/null +++ b/db/migrate/20240726083742_alter_suppliers_sharing_fields.rb @@ -0,0 +1,19 @@ +class AlterSuppliersSharingFields < ActiveRecord::Migration[5.2] + def up + change_table :suppliers do |t| + t.remove :shared_supplier_id + t.column :supplier_remote_source, :string + t.column :external_uuid, :string + end + + add_index :suppliers, :external_uuid, unique: true + end + + def down + change_table :suppliers do |t| + t.column :shared_supplier_id, :integer + t.remove :supplier_remote_source + t.remove :external_uuid + end + end +end diff --git a/db/migrate/20240726083743_create_article_units.rb b/db/migrate/20240726083743_create_article_units.rb new file mode 100644 index 000000000..bf19288c7 --- /dev/null +++ b/db/migrate/20240726083743_create_article_units.rb @@ -0,0 +1,37 @@ +class CreateArticleUnits < ActiveRecord::Migration[5.2] + def up + create_table :article_units, id: false do |t| + t.string :unit, length: 3, null: false + + t.timestamps + end + + add_index :article_units, :unit, unique: true + + unit_codes = ArticleUnitsLib::DEFAULT_PIECE_UNIT_CODES + ArticleUnitsLib::DEFAULT_METRIC_SCALAR_UNIT_CODES + + unit_codes += ArticleUnitsLib::DEFAULT_IMPERIAL_SCALAR_UNIT_CODES if imperial_plain_text_units_exist? + + unit_codes.each do |unit_code| + insert(%{ + INSERT INTO article_units (unit, created_at, updated_at) + VALUES ( + #{quote unit_code}, + NOW(), + NOW() + ) + }) + end + end + + def down + drop_table :article_units + end + + protected + + def imperial_plain_text_units_exist? + plain_text_units = select_all('SELECT DISTINCT unit FROM article_versions').pluck('unit') + plain_text_units.any? { |plain_text_unit| /(?:\s|[0-9])+(?:oz|lb)\s*$/.match(plain_text_unit) } + end +end diff --git a/db/migrate/20240726083744_add_unit_migration_completed_to_suppliers.rb b/db/migrate/20240726083744_add_unit_migration_completed_to_suppliers.rb new file mode 100644 index 000000000..497e00772 --- /dev/null +++ b/db/migrate/20240726083744_add_unit_migration_completed_to_suppliers.rb @@ -0,0 +1,5 @@ +class AddUnitMigrationCompletedToSuppliers < ActiveRecord::Migration[5.2] + def change + add_column :suppliers, :unit_migration_completed, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 9a34fa45c..c4dbfbb98 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_06_26_124329) do +ActiveRecord::Schema[7.0].define(version: 2024_07_26_083744) do create_table "action_text_rich_texts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.string "name", null: false t.text "body", size: :long @@ -55,38 +55,54 @@ t.index ["name"], name: "index_article_categories_on_name", unique: true end - create_table "article_prices", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "article_unit_ratios", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.bigint "article_version_id", null: false + t.integer "sort", null: false + t.decimal "quantity", precision: 38, scale: 3, null: false + t.string "unit" + t.index ["article_version_id"], name: "index_article_unit_ratios_on_article_version_id" + t.index ["sort"], name: "index_article_unit_ratios_on_sort" + end + + create_table "article_units", id: false, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.string "unit", null: false + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + t.index ["unit"], name: "index_article_units_on_unit", unique: true + end + + create_table "article_versions", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.integer "article_id", null: false - t.decimal "price", precision: 8, scale: 2, default: "0.0", null: false + t.decimal "price", precision: 11, scale: 6, default: "0.0", null: false, comment: "stored in `article_versions.supplier_order_unit`" t.decimal "tax", precision: 8, scale: 2, default: "0.0", null: false t.decimal "deposit", precision: 8, scale: 2, default: "0.0", null: false - t.integer "unit_quantity" - t.datetime "created_at", precision: nil - t.index ["article_id"], name: "index_article_prices_on_article_id" - end - - create_table "articles", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.datetime "created_at" t.string "name", default: "", null: false - t.integer "supplier_id", default: 0, null: false t.integer "article_category_id", default: 0, null: false - t.string "unit", default: "", null: false + t.string "unit" t.string "note" t.boolean "availability", default: true, null: false t.string "manufacturer" t.string "origin" - t.datetime "shared_updated_on", precision: nil - t.decimal "price", precision: 8, scale: 2 - t.float "tax" - t.decimal "deposit", precision: 8, scale: 2, default: "0.0" - t.integer "unit_quantity", default: 1, null: false t.string "order_number" - t.datetime "created_at", precision: nil t.datetime "updated_at", precision: nil + t.string "supplier_order_unit" + t.string "price_unit" + t.string "billing_unit" + t.string "group_order_unit" + t.decimal "group_order_granularity", precision: 8, scale: 3, default: "1.0", null: false + t.float "minimum_order_quantity" + t.index ["article_category_id"], name: "index_article_versions_on_article_category_id" + t.index ["article_id", "created_at"], name: "index_article_versions_on_article_id_and_created_at", unique: true + end + + create_table "articles", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.integer "supplier_id", default: 0, null: false + t.datetime "shared_updated_on", precision: nil + t.datetime "created_at", precision: nil t.datetime "deleted_at", precision: nil t.string "type" t.integer "quantity", default: 0 - t.index ["article_category_id"], name: "index_articles_on_article_category_id" - t.index ["name", "supplier_id"], name: "index_articles_on_name_and_supplier_id" t.index ["supplier_id"], name: "index_articles_on_supplier_id" t.index ["type"], name: "index_articles_on_type" end @@ -181,8 +197,8 @@ create_table "group_order_article_quantities", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.integer "group_order_article_id", default: 0, null: false - t.integer "quantity", default: 0 - t.integer "tolerance", default: 0 + t.decimal "quantity", precision: 8, scale: 3, default: "0.0", null: false + t.decimal "tolerance", precision: 8, scale: 3, default: "0.0", null: false t.datetime "created_on", precision: nil, null: false t.index ["group_order_article_id"], name: "index_group_order_article_quantities_on_group_order_article_id" end @@ -190,8 +206,8 @@ create_table "group_order_articles", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.integer "group_order_id", default: 0, null: false t.integer "order_article_id", default: 0, null: false - t.integer "quantity", default: 0, null: false - t.integer "tolerance", default: 0, null: false + t.decimal "quantity", precision: 8, scale: 3, default: "0.0", null: false + t.decimal "tolerance", precision: 8, scale: 3, default: "0.0", null: false t.datetime "updated_on", precision: nil, null: false t.decimal "result", precision: 8, scale: 3 t.decimal "result_computed", precision: 8, scale: 3 @@ -346,15 +362,15 @@ create_table "order_articles", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.integer "order_id", default: 0, null: false - t.integer "article_id", default: 0, null: false - t.integer "quantity", default: 0, null: false - t.integer "tolerance", default: 0, null: false - t.integer "units_to_order", default: 0, null: false + t.decimal "quantity", precision: 8, scale: 3, default: "0.0", null: false, comment: "stored in `article_versions.group_order_unit`" + t.decimal "tolerance", precision: 8, scale: 3, default: "0.0", null: false, comment: "stored in `article_versions.group_order_unit`" + t.decimal "units_to_order", precision: 11, scale: 6, default: "0.0", null: false, comment: "stored in `article_versions.supplier_order_unit`" t.integer "lock_version", default: 0, null: false - t.integer "article_price_id" - t.decimal "units_billed", precision: 8, scale: 3 - t.decimal "units_received", precision: 8, scale: 3 - t.index ["order_id", "article_id"], name: "index_order_articles_on_order_id_and_article_id", unique: true + t.integer "article_version_id", null: false + t.decimal "units_billed", precision: 11, scale: 6, comment: "stored in `article_versions.supplier_order_unit`" + t.decimal "units_received", precision: 11, scale: 6, comment: "stored in `article_versions.supplier_order_unit`" + t.index ["article_version_id"], name: "index_order_articles_on_article_version_id" + t.index ["order_id", "article_version_id"], name: "index_order_articles_on_order_id_and_article_version_id", unique: true t.index ["order_id"], name: "index_order_articles_on_order_id" end @@ -520,12 +536,15 @@ t.string "delivery_days" t.string "order_howto" t.string "note" - t.integer "shared_supplier_id" t.string "min_order_quantity" t.datetime "deleted_at", precision: nil t.string "shared_sync_method" t.string "iban" - t.integer "supplier_category_id" + t.integer "supplier_category_id", null: false + t.string "supplier_remote_source" + t.string "external_uuid" + t.datetime "unit_migration_completed", precision: nil + t.index ["external_uuid"], name: "index_suppliers_on_external_uuid", unique: true t.index ["name"], name: "index_suppliers_on_name", unique: true end diff --git a/db/seeds.rb b/db/seeds.rb index 37a996ffe..f47d42ca0 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,4 +1,4 @@ # default seed is minimal -require Rails.root.join('db/seeds/minimal.seeds.rb') +require Rails.root.join('db/seeds/small.en.seeds.rb') # to generate new seeds, use the seed_dumper gem diff --git a/db/seeds/seed_helper.rb b/db/seeds/seed_helper.rb index 05272319d..360e6e1ed 100644 --- a/db/seeds/seed_helper.rb +++ b/db/seeds/seed_helper.rb @@ -10,7 +10,7 @@ def seed_group_orders go = og.group_orders.create!(order: order, updated_by_user_id: 1) rand(3..12).times do goa = go.group_order_articles.find_or_create_by!(order_article: order.order_articles.offset(rand(noas)).first) - unit_quantity = goa.order_article.price.unit_quantity + unit_quantity = goa.order_article.article_version.unit_quantity goa.update_quantities rand([4, (unit_quantity * 2) + 2].max), rand(unit_quantity) end end diff --git a/db/seeds/small.en.seeds.rb b/db/seeds/small.en.seeds.rb index 6c832e1d4..8f9960c3f 100644 --- a/db/seeds/small.en.seeds.rb +++ b/db/seeds/small.en.seeds.rb @@ -5,6 +5,11 @@ FinancialTransactionClass.create!(id: 1, name: 'Standard') FinancialTransactionClass.create!(id: 2, name: 'Foodsoft') +## Article units + +unit_codes = ArticleUnitsLib::DEFAULT_PIECE_UNIT_CODES + ArticleUnitsLib::DEFAULT_METRIC_SCALAR_UNIT_CODES +unit_codes.each { |unit_code| ArticleUnit.create!(unit: unit_code) } + ## Suppliers & articles SupplierCategory.create!(id: 1, name: 'Other', financial_transaction_class_id: 1) @@ -17,7 +22,11 @@ { id: 3, name: 'Cheesemaker', supplier_category_id: 1, address: 'Cheesestreet 5, London', phone: '0123456789', url: 'http://www.cheesemaker.test/' }, { id: 4, name: 'The Nuthome', supplier_category_id: 1, - address: 'Alexanderplatz, Berlin', phone: '0123456789', email: 'info@thenuthome.test', url: 'http://www.thenuthome.test/', note: 'delivery in Berlin; €9 delivery costs for orders under €123' } + address: 'Alexanderplatz, Berlin', phone: '0123456789', email: 'info@thenuthome.test', url: 'http://www.thenuthome.test/', note: 'delivery in Berlin; €9 delivery costs for orders under €123' }, + { id: 5, name: 'Farmer John', supplier_category_id: 1, address: 'Smallstreet 1, Cookilage', + phone: '0123456789', email: 'info@john.com', min_order_quantity: '100', unit_migration_completed: Time.now }, + { id: 6, name: 'Unit migration test', supplier_category_id: 1, address: 'Smallstreet 2, Cookilage', + phone: '0123456789', email: 'info@bbakery.test', min_order_quantity: '100', unit_migration_completed: nil } ]) ArticleCategory.create!(id: 1, name: 'Other', description: 'other, misc, unknown') @@ -36,222 +45,259 @@ ArticleCategory.create!(id: 13, name: 'Nuts & Seeds') ArticleCategory.create!(id: 14, name: 'Sugar & Sweets') -Article.create!(name: 'Brown whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brown half', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brown sesame whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brown sesame half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Light wheat whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Light wheat half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bread with sunflower seeds whole', supplier_id: 1, article_category_id: 5, - unit: 'pc', note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bread with sunflower seeds half', supplier_id: 1, article_category_id: 5, - unit: 'pc', note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bread with walnuts whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bread with walnuts half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kennemerlandbread whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kennemerlandbread half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Maize bread whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Maize bread half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 1200 gram whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 1200 gram half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 900 gram whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 900 gram half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Speltbread whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Speltbread half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Country bread 900gram whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Country bread 900gram half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'White whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'White half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'White with poppy seeds whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'White with poppy seeds half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Fig bread whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Fig bread half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Beer-based bread whole', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Beer-based bread half', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Raisin bun', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.99E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Muesli bun', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brioche', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.99E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brown croissant', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Croissants', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Cheese croissants', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolatecroissants', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Soepstengels white', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Soepstengels volkoren', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.99E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Pumpkin-seed buns', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.88E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'White buns', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.66E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brown buns', supplier_id: 1, article_category_id: 5, unit: 'pc', note: 'organic', - availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.66E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Tomato-feta bread', supplier_id: 1, article_category_id: 5, unit: 'pc', - note: 'organic', availability: true, manufacturer: 'The Baker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolate Bar Milk (37%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolate Bar Pure (68%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolate Bar Milk (40%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolate Bar Pure (75%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocolate Bar Swan Pure (75%)', supplier_id: 2, article_category_id: 14, - unit: '120gr', note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.66E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Cacao nibs', supplier_id: 2, article_category_id: 14, unit: '1 kg', - note: 'organic', availability: true, manufacturer: 'Chocolatemakers', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Cheese Cow-young', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.88E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- young matured', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- matured', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 12) -Article.create!(name: 'Cheese cow- extra matured', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.12E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'cheese Cow- old', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'cheese cow -very old', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.12E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese Cow-nettle young', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- nettle young matured', supplier_id: 3, article_category_id: 8, - unit: 'kg', note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.1075E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- nettle matured', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese Cow-cumin young', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- cumin young matured', supplier_id: 3, article_category_id: 8, - unit: 'kg', note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.1075E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cheese cow- cumin matured', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'organic', availability: true, manufacturer: 'Cheesefarm', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cashew nuts', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.4444E2, tax: 6.0, deposit: 0.0, unit_quantity: 22, order_number: ':b936051') -Article.create!(name: 'Hazel white', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':9e3f85b') -Article.create!(name: 'Hazel brown', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':d278041') -Article.create!(name: 'Almond Brown Spanish', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.999E1, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':0b51a8d') -Article.create!(name: 'Brazil nuts (organic)', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 20, order_number: ':01e59e3') -Article.create!(name: 'Organic walnut light halves', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':7ff8587') -Article.create!(name: 'Pinenuts', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'organic', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':aa88d9f') -Article.create!(name: 'Pumpkin', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'organic', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':e63069b') -Article.create!(name: 'Sunflower seeds (organic)', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.999E1, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':0428388') -Article.create!(name: 'Amandel White Spaans', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'organic', availability: true, price: 0.66666E3, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':a8f0734') -Article.create!(name: 'Cashew', supplier_id: 4, article_category_id: 13, unit: 'kg', availability: true, - price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':1d26958') -Article.create!(name: 'Almonds blanched', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':31439e2') -Article.create!(name: 'Almonds natural', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':9c49374') -Article.create!(name: 'Walnut ELH halves', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.4444E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':92907d1') -Article.create!(name: 'Walnut ELP parts', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':395640e') -Article.create!(name: 'Brazil nuts', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':710acbb') -Article.create!(name: 'Macadamia type 0', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':bbaf40b') -Article.create!(name: 'Pecan', supplier_id: 4, article_category_id: 13, unit: 'kg', availability: true, - price: 0.55555E3, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':7958183') -Article.create!(name: 'Hazelnuts natural', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':50392a8') -Article.create!(name: 'Hazelnuts blanched', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':4fe6525') -Article.create!(name: 'Mixed Nuts', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c051b22') -Article.create!(name: 'Peanuts', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.777E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':f507577') -Article.create!(name: 'Small peanuts', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':ce563bb') -Article.create!(name: 'Medjoul dates', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':8232061') -Article.create!(name: 'Turkish apricots natural', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':185084f') -Article.create!(name: 'Turkish apricots sulfurised', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':2b2fb20') -Article.create!(name: 'Spanish Figs', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.444E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':82590b1') -Article.create!(name: 'Turkish Figs', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.555E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':cabeeb6') -Article.create!(name: 'Sour Apricots South-Africa', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':2ac18b7') -Article.create!(name: 'Blue raisins Flames', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':16bfa75') -Article.create!(name: 'Yellow Raisins', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':1c59324') -Article.create!(name: 'Red Raisins', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c3fcd84') -Article.create!(name: 'Cranberries whole', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.222E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':921c168') -Article.create!(name: 'Dried apples', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.555E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':902c67b') -Article.create!(name: 'Dried plums without core', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.222E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':a847f91') -Article.create!(name: 'Pumpkin seeds', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.111E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':535645f') -Article.create!(name: 'Sunflower seeds', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.666E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':4ab9a83') -Article.create!(name: 'Linseed', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55E0, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':04be223') -Article.create!(name: 'Poppy seeds', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.7777E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':ec5b2b9') -Article.create!(name: 'Pine nuts medium china', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':0e5b0b8') -Article.create!(name: 'Goji berries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':d52ee00') -Article.create!(name: 'Mulberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.5555E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':5f46bd5') -Article.create!(name: 'Peeled Hemp', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.5555E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c39165b') -Article.create!(name: 'Incaberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':8d44fe7') -Article.create!(name: 'Blueberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':9a95422') -Article.create!(name: 'Chia seeds', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55555E3, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':416d57b') -Article.create!(name: 'Coconut grated', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55E0, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':b3f65e4') +### Beautiful bakery + +[ + { name: 'Brown whole', price: 0.22E1 }, + { name: 'Brown half', price: 0.11E1 }, + { name: 'Brown sesame whole', price: 0.22E1 }, + { name: 'Brown sesame half', price: 0.11E1 }, + { name: 'Light wheat whole', price: 0.22E1 }, + { name: 'Light wheat half', price: 0.11E1 }, + { name: 'Bread with sunflower seeds whole', price: 0.33E1 }, + { name: 'Bread with sunflower seeds half', price: 0.11E1 }, + { name: 'Bread with walnuts whole', price: 0.33E1 }, + { name: 'Bread with walnuts half', price: 0.11E1 }, + { name: 'Kennemerlandbread whole', price: 0.33E1 }, + { name: 'Kennemerlandbread half', price: 0.11E1 }, + { name: 'Maize bread whole', price: 0.33E1 }, + { name: 'Maize bread half', price: 0.11E1 }, + { name: 'Oberlander 1200 gram whole', price: 0.33E1 }, + { name: 'Oberlander 1200 gram half', price: 0.11E1 }, + { name: 'Oberlander 900 gram whole', price: 0.33E1 }, + { name: 'Oberlander 900 gram half', price: 0.11E1 }, + { name: 'Speltbread whole', price: 0.33E1 }, + { name: 'Speltbread half', price: 0.11E1 }, + { name: 'Country bread 900gram whole', price: 0.33E1 }, + { name: 'Country bread 900gram half', price: 0.11E1 }, + { name: 'White whole', price: 0.33E1 }, + { name: 'White half', price: 0.11E1 }, + { name: 'White with poppy seeds whole', price: 0.33E1 }, + { name: 'White with poppy seeds half', price: 0.11E1 }, + { name: 'Fig bread whole', price: 0.33E1 }, + { name: 'Fig bread half', price: 0.11E1 }, + { name: 'Beer-based bread whole', price: 0.33E1 }, + { name: 'Beer-based bread half', price: 0.22E1 }, + { name: 'Raisin bun', price: 0.99E0 }, + { name: 'Muesli bun', price: 0.11E1 }, + { name: 'Brioche', price: 0.99E0 }, + { name: 'Brown croissant', price: 0.11E1 }, + { name: 'Croissants', price: 0.11E1 }, + { name: 'Cheese croissants', price: 0.11E1 }, + { name: 'Chocolatecroissants', price: 0.11E1 }, + { name: 'Soepstengels white', price: 0.11E1 }, + { name: 'Soepstengels whole grain', price: 0.99E0 }, + { name: 'Pumpkin-seed buns', price: 0.88E0 }, + { name: 'White buns', price: 0.66E0 }, + { name: 'Brown buns', price: 0.66E0 }, + { name: 'Tomato-feta bread', price: 0.11E1 } + +].each do |a| + Article.create!({ supplier_id: 1, + quantity: 0 }) + .article_versions.create({ name: a[:name], + note: 'organic', + availability: true, + manufacturer: 'The Baker', + article_category_id: 5, + unit: nil, + price: a[:price], + tax: 6.0, + deposit: '0.0', + supplier_order_unit: 'XPP', + price_unit: 'XPP', + billing_unit: 'XPP', + group_order_unit: 'XPP' }) +end + +### Chocolatiers + +[ + { name: 'Chocolate Bar Milk (37%)', price: '0.22E1', quantity: 90 }, + { name: 'Chocolate Bar Pure (68%)', price: '0.22E1', quantity: 90 }, + { name: 'Chocolate Bar Milk (40%)', price: '0.22E1', quantity: 90 }, + { name: 'Chocolate Bar Pure (75%)', price: '0.22E1', quantity: 90 }, + { name: 'Chocolate Bar Swan Pure (75%)', price: '0.66E1', quantity: 120 }, + { name: 'Cacao nibs', price: '0.10E2', quantity: 1 } +].each do |a| + Article.create!({ supplier_id: 2, + quantity: 0 }) + .article_versions.create({ name: a[:name], + note: 'organic', + availability: true, + manufacturer: 'Chocolatemakers', + article_category_id: 14, + unit: nil, + price: a[:price], + tax: 6.0, + deposit: '0.0', + supplier_order_unit: 'XPP', + price_unit: 'XPP', + billing_unit: 'XPP', + group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: a[:quantity], unit: 'KGM' })] }) +end + +### Cheesemaker + +[ + { name: 'Cheese Cow-young', price: 0.88E1, quantity: 8 }, + { name: 'Cheese cow- young matured', price: 0.99E1, quantity: 8 }, + { name: 'Cheese cow- matured', price: 0.11E2, quantity: 12 }, + { name: 'Cheese cow- extra matured', price: 0.12E2, quantity: 8 }, + { name: 'cheese Cow- old', price: 0.11E2, quantity: 8 }, + { name: 'cheese cow -very old', price: 0.12E2, quantity: 8 }, + { name: 'Cheese Cow-nettle young', price: 0.99E1, quantity: 8 }, + { name: 'Cheese cow- nettle young matured', price: 0.1075E2, quantity: 8 }, + { name: 'Cheese cow- nettle matured', price: 0.11E2, quantity: 8 }, + { name: 'Cheese Cow-cumin young', price: 0.99E1, quantity: 8 }, + { name: 'Cheese cow- cumin young matured', price: 0.1075E2, quantity: 8 }, + { name: 'Cheese cow- cumin matured', price: 0.11E2, quantity: 8 } +].each do |a| + Article.create!({ supplier_id: 3, + quantity: 0 }) + .article_versions.create({ name: a[:name], + note: 'organic', + origin: 'NL', + availability: true, + manufacturer: 'Cheesefarm', + article_category_id: 8, + unit: nil, + price: a[:price], + tax: 6.0, + deposit: '0.0', + supplier_order_unit: 'XPP', + price_unit: 'XPP', + billing_unit: 'XPP', + group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: a[:quantity], unit: 'KGM' })] }) +end + +### The Nuthome +[ + { order_number: ':b936051', name: 'Cashew nuts', price: 0.4444E2, quantity: 22 }, + { order_number: ':9e3f85b', name: 'White hazelnuts', price: 0.3333E2, quantity: 10 }, + { order_number: ':d278041', name: 'Brown hazelnuts', price: 0.1111E2, quantity: 10 }, + { order_number: ':0b51a8d', name: 'Spanish almond brown', price: 0.999E1, quantity: 10 }, + { order_number: ':01e59e3', name: 'Brazil nuts (organic)', price: 0.6666E2, quantity: 20 }, + { order_number: ':7ff8587', name: 'Organic light walnut halves', price: 0.333E1, quantity: 10 }, + { order_number: ':aa88d9f', name: 'Pine nuts', price: 0.888E1, quantity: 25 }, + { order_number: ':e63069b', name: 'Pumpkin', price: 0.1111E2, quantity: 25 }, + { order_number: ':0428388', name: 'Sunflower seeds (organic)', price: 0.999E1, quantity: 25 }, + { order_number: ':a8f0734', name: 'Spanish almond white', price: 0.66666E3, quantity: 10 }, + { order_number: ':1d26958', name: 'Cashews', price: 0.6666E2, quantity: 1 }, + { order_number: ':31439e2', name: 'Blanched almonds', price: 0.333E1, quantity: 1 }, + { order_number: ':9c49374', name: 'Natural almonds', price: 0.1111E2, quantity: 1 }, + { order_number: ':92907d1', name: 'Walnut ELH halves', price: 0.4444E2, quantity: 1 }, + { order_number: ':395640e', name: 'Walnut ELP pieces', price: 0.8888E2, quantity: 1 }, + { order_number: ':710acbb', name: 'Brazil nuts', price: 0.8888E2, quantity: 1 }, + { order_number: ':bbaf40b', name: 'Macadamia Style 0', price: 0.3333E2, quantity: 1 }, + { order_number: ':7958183', name: 'Pecans', price: 0.55555E3, quantity: 1 }, + { order_number: ':50392a8', name: 'Natural hazelnuts', price: 0.6666E2, quantity: 1 }, + { order_number: ':4fe6525', name: 'Blanched hazelnuts', price: 0.3333E2, quantity: 1 }, + { order_number: ':c051b22', name: 'Mixed nuts', price: 0.333E1, quantity: 1 }, + { order_number: ':f507577', name: 'Peanuts', price: 0.777E1, quantity: 1 }, + { order_number: ':ce563bb', name: 'Peanuts without skin (small)', price: 0.8888E2, quantity: 1 }, + { order_number: ':8232061', name: 'Medjool dates', price: 0.3333E2, quantity: 1 }, + { order_number: ':185084f', name: 'Turkish unsulphured apricots', price: 0.888E1, quantity: 1 }, + { order_number: ':2b2fb20', name: 'Turkish sulphured apricots', price: 0.1111E2, quantity: 1 }, + { order_number: ':82590b1', name: 'Spanish figs', price: 0.444E1, quantity: 1 }, + { order_number: ':cabeeb6', name: 'Turkish figs', price: 0.555E1, quantity: 1 }, + { order_number: ':2ac18b7', name: 'South African unsulphured apricots', price: 0.1111E2, quantity: 1 }, + { order_number: ':16bfa75', name: 'Blue raisins Flames', price: 0.1111E2, quantity: 1 }, + { order_number: ':1c59324', name: 'Yellow raisins', price: 0.2222E2, quantity: 1 }, + { order_number: ':c3fcd84', name: 'Red raisins', price: 0.1111E2, quantity: 1 }, + { order_number: ':921c168', name: 'Whole cranberries', price: 0.222E1, quantity: 1 }, + { order_number: ':902c67b', name: 'Dried apple pieces', price: 0.555E1, quantity: 1 }, + { order_number: ':a847f91', name: 'Pitted dried plums', price: 0.222E1, quantity: 1 }, + { order_number: ':535645f', name: 'Pumpkin seeds', price: 0.111E1, quantity: 1 }, + { order_number: ':4ab9a83', name: 'Sunflower seeds', price: 0.666E1, quantity: 1 }, + { order_number: ':04be223', name: 'Flaxseeds', price: 0.55E0, quantity: 1 }, + { order_number: ':ec5b2b9', name: 'Poppy seeds', price: 0.7777E2, quantity: 1 }, + { order_number: ':0e5b0b8', name: 'Pine nuts medium China', price: 0.2222E2, quantity: 1 }, + { order_number: ':d52ee00', name: 'Goji berries', price: 0.888E1, quantity: 1 }, + { order_number: ':5f46bd5', name: 'Mulberries', price: 0.5555E2, quantity: 1 }, + { order_number: ':c39165b', name: 'Shelled hemp seeds', price: 0.5555E2, quantity: 1 }, + { order_number: ':8d44fe7', name: 'Incaberries', price: 0.888E1, quantity: 1 }, + { order_number: ':9a95422', name: 'Blueberries', price: 0.2222E2, quantity: 1 }, + { order_number: ':416d57b', name: 'Chia seeds', price: 0.55555E3, quantity: 1 }, + { order_number: ':b3f65e4', name: 'Coconut rasp', price: 0.55E0, quantity: 1 } +].each do |a| + Article.create!({ supplier_id: 4, + quantity: 0 }) + .article_versions.create({ name: a[:name], + note: 'organic', + availability: true, + manufacturer: 'The Nuthome', + order_number: a[:order_number], + article_category_id: 13, + unit: nil, + price: a[:price], + tax: 6.0, + deposit: '0.0', + supplier_order_unit: 'XPP', + price_unit: 'XPP', + billing_unit: 'XPP', + group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: a[:quantity], unit: 'KGM' })] }) +end + +### Farmer John + +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Carrots', article_category_id: 3, unit: nil, price: 3, tax: 7.0, + deposit: '0.0', supplier_order_unit: 'KGM', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.001 }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Pumpkin', article_category_id: 3, unit: nil, price: 1.5, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 1.3, unit: 'KGM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Bread', article_category_id: 5, unit: nil, price: 2.1, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'XPP', group_order_granularity: 0.5, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 700, unit: 'GRM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Bread rolls', article_category_id: 5, unit: nil, price: 1, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'XPP', group_order_unit: 'XPP', minimum_order_quantity: 5, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 350, unit: 'GRM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Muesli', article_category_id: 13, unit: nil, price: 2.5, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'XPP', billing_unit: 'XPP', group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 500, unit: 'GRM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Smoked tofu', article_category_id: 8, unit: nil, price: 2.4, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'HGM', billing_unit: 'GRM', group_order_unit: 'XPP', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 160, unit: 'GRM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Beer', article_category_id: 6, unit: nil, price: 52, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XCR', price_unit: 'XBO', billing_unit: 'XBO', group_order_unit: 'XBO', + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 20, unit: 'XBO' }), ArticleUnitRatio.new({ sort: 2, quantity: 10, unit: 'LTR' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Detergent', article_category_id: 1, unit: nil, price: 20, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'LTR', billing_unit: 'LTR', group_order_unit: 'LTR', group_order_granularity: 0.001, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 2, quantity: 20, unit: 'LTR' }), ArticleUnitRatio.new({ sort: 2, quantity: 25, unit: 'KGM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Rice', article_category_id: 12, unit: nil, price: 6.75, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.05, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 25, unit: 'KGM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Potatoes', article_category_id: 3, unit: nil, price: 1.5, tax: 7.0, + deposit: '0.0', supplier_order_unit: 'KGM', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'GRM' }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Wheat', article_category_id: 12, unit: nil, price: 25, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.05, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 25, unit: 'KGM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Oranges', article_category_id: 2, unit: nil, price: 36, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.05, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 12, unit: 'KGM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Lentils', article_category_id: 12, unit: nil, price: 2.7, tax: 7.0, deposit: '0.0', supplier_order_unit: 'XPP', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.05, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 500, unit: 'GRM' })] }) +Article.create!({ supplier_id: 5, + quantity: 0 }).article_versions.create({ name: 'Oyster mushrooms', article_category_id: 3, unit: nil, + price: 3, tax: 7.0, deposit: '0.0', supplier_order_unit: 'KGM', price_unit: 'KGM', billing_unit: 'KGM', group_order_unit: 'KGM', group_order_granularity: 0.001, minimum_order_quantity: 1.2 }) + +### Unit migration test + +Article.create!({ supplier_id: 6, + quantity: 0 }).article_versions.create({ name: 'Goat cheese', article_category_id: 8, unit: '250g', price: 3, tax: 7.0, + deposit: '0.0', supplier_order_unit: nil, price_unit: nil, billing_unit: nil, group_order_unit: nil, group_order_granularity: 1 }) +Article.create!({ supplier_id: 6, + quantity: 0 }).article_versions.create({ name: 'Butter', article_category_id: 8, unit: '4x250g', price: 3, tax: 7.0, deposit: '0.0', supplier_order_unit: nil, price_unit: 'XPP', billing_unit: 'XPP', group_order_unit: 'XPP', group_order_granularity: 1, + article_unit_ratios: [ArticleUnitRatio.new({ sort: 1, quantity: 4, unit: 'XPP' })] }) +Article.create!({ supplier_id: 6, + quantity: 0 }).article_versions.create({ name: 'Bread', article_category_id: 5, unit: 'pc', price: 3, tax: 7.0, + deposit: '0.0', supplier_order_unit: nil, price_unit: nil, billing_unit: nil, group_order_unit: nil, group_order_granularity: 1 }) ## Members & groups @@ -301,6 +347,8 @@ seed_order(supplier_id: 1, starts: 2.days.ago, ends: 5.days.from_now) seed_order(supplier_id: 3, starts: 3.days.ago, ends: 5.days.from_now) seed_order(supplier_id: 2, starts: 4.days.ago, ends: 4.days.from_now) +seed_order(supplier_id: 4, starts: 1.day.ago, ends: 10.days.from_now) +seed_order(supplier_id: 5, starts: 10.days.ago, ends: 1.day.from_now) ## GroupOrders & such @@ -320,3 +368,5 @@ created_on: 'Wed, 05 Feb 2014 16:49:24 UTC +00:00', financial_transaction_type_id: 1) FinancialTransaction.create!(id: 6, ordergroup_id: 8, amount: 0.90E2, note: 'Bank transfer', user_id: 2, created_on: 'Mon, 17 Feb 2014 16:19:34 UTC +00:00', financial_transaction_type_id: 1) +FinancialTransaction.create!(id: 7, ordergroup_id: 5, amount: 5000, note: 'Bank transfer', user_id: 1, + created_on: 'Mon, 18 Feb 2014 16:19:34 UTC +00:00', financial_transaction_type_id: 1) diff --git a/db/seeds/small.nl.seeds.rb b/db/seeds/small.nl.seeds.rb deleted file mode 100644 index 1dd399923..000000000 --- a/db/seeds/small.nl.seeds.rb +++ /dev/null @@ -1,322 +0,0 @@ -require_relative 'seed_helper' - -## Financial transaction classes - -FinancialTransactionClass.create!(id: 1, name: 'Standaard') -FinancialTransactionClass.create!(id: 2, name: 'Foodsoft') - -## Suppliers & articles - -SupplierCategory.create!(id: 1, name: 'Other', financial_transaction_class_id: 1) - -Supplier.create!([ - { id: 1, name: 'Koekenbakker', supplier_category_id: 1, - address: 'Dorpsstraat 1, Koekange', phone: '012 3456789', email: 'info@dekoekenbakker.test', min_order_quantity: '100' }, - { id: 2, name: 'Chocolademakkers', supplier_category_id: 1, - address: 'Multatuliweg 1, Amsterdam', phone: '012 3456789', email: 'info@chocolademakkers.test', url: 'http://www.chocolademakkers.test/', contact_person: 'Max Puur', delivery_days: 'di, vr (Amsterdam)' }, - { id: 3, name: 'Kaasmaker', supplier_category_id: 1, address: 'Waagplein, Alkmaar', - phone: '012 3456789', url: 'http://www.kaaskamer.test/' }, - { id: 4, name: 'Notenhuis', supplier_category_id: 1, address: 'Damrak 1, Amsterdam', - phone: '012 3456789', email: 'info@notenhuis.test', url: 'http://www.notenhuis.test/', note: 'leveren in Amsterdam; €9 leverkosten bij bestellingen onder €123' } - ]) - -ArticleCategory.create!(id: 1, name: 'Other', description: 'overig, anders, onbekend') -ArticleCategory.create!(id: 2, name: 'Fruit') -ArticleCategory.create!(id: 3, name: 'Groenten') -ArticleCategory.create!(id: 4, name: 'Aardappels & uien') -ArticleCategory.create!(id: 5, name: 'Brood & Bakkerij') -ArticleCategory.create!(id: 6, name: 'Dranken', description: 'sap, fruitsap, groentesap, frisdrank') -ArticleCategory.create!(id: 7, name: 'Kruiden', - description: 'kruiden, specerijen, conserveringsmiddelen, extracten') -ArticleCategory.create!(id: 8, name: 'Zuivel', - description: 'melk, boter, room, yoghurt, kaas, eieren, zuivelvervangers') -ArticleCategory.create!(id: 9, name: 'Vis & Zee', description: 'vis, schaaldieren, schelpdieren') -ArticleCategory.create!(id: 10, name: 'Vlees & Gevogelte') -ArticleCategory.create!(id: 11, name: 'Oliën & Vetten') -ArticleCategory.create!(id: 12, name: 'Graan & Peulvruchten') -ArticleCategory.create!(id: 13, name: 'Noten & Zaden') -ArticleCategory.create!(id: 14, name: 'Zoetwaren & Zoetstof') - -Article.create!(name: 'Volkoren heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Volkoren half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Volkoren sesam heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Volkoren sesam half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Licht tarwe heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Licht tarwe half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Zonnebloempitbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Zonnebloempitbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Walnoten vloer heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Walnoten vloer half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kennemerlandbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kennemerlandbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Maisbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Maisbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 1200 gram heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 1200 gram half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 900 gram heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Oberlander 900 gram half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Speltbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Speltbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Landbrood 900gram heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Landbrood 900gram half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Wit heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Wit half', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Wit met maanzaad heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Wit met maanzaad half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Vijgenbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Vijgenbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bierborstelbrood heel', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.33E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bierborstelbrood half', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Krentenbol', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.99E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Mueslibol', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Brioche', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.91E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Volkoren croissant', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Croissants', supplier_id: 1, article_category_id: 5, unit: 'stuk', note: 'bio', - availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kaas croissants', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladecroissants', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Soepstengels wit', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Soepstengels volkoren', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.99E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Pompoenpitten broodjes', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.88E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Witte kadetjes', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.66E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Bruine kadetjes', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.66E0, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Tomaten feta broodje', supplier_id: 1, article_category_id: 5, unit: 'stuk', - note: 'bio', availability: true, manufacturer: 'De Bakker', origin: 'NL', price: 0.11E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladereep Melk (37%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'bio', availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladereep Puur (68%)', supplier_id: 2, article_category_id: 14, unit: '90gr', - note: 'bio', availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladereep Drie Mensen Melk (40%)', supplier_id: 2, article_category_id: 14, - unit: '90gr', note: 'bio', availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladereep Drie Mensen Puur (75%)', supplier_id: 2, article_category_id: 14, - unit: '90gr', note: 'bio', availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.22E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Chocoladereep Zwaan Puur (75%)', supplier_id: 2, article_category_id: 14, - unit: '120gr', note: 'bio', availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.66E1, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Cacao nibs', supplier_id: 2, article_category_id: 14, unit: '1 kg', note: 'bio', - availability: true, manufacturer: 'Chocolademakkers', origin: 'NL', price: 0.10E2, tax: 6.0, deposit: 0.0, unit_quantity: 1) -Article.create!(name: 'Kaas Koe-jong', supplier_id: 3, article_category_id: 8, unit: 'kg', note: 'bio', - availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.88E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- jong belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 12) -Article.create!(name: 'Kaas koe- extra belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'kaas Koe- oud', supplier_id: 3, article_category_id: 8, unit: 'kg', note: 'bio', - availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.1375E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'kaas koe -overjarig', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas Koe-brandnetel jong', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- brandnetel jong belegen', supplier_id: 3, article_category_id: 8, - unit: 'kg', note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- brandnetel belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas Koe-komijn jong', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.99E1, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- komijn jong belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Kaas koe- komijn belegen', supplier_id: 3, article_category_id: 8, unit: 'kg', - note: 'bio', availability: true, manufacturer: 'Kaasboerderij', origin: 'NL', price: 0.11E2, tax: 6.0, deposit: 0.0, unit_quantity: 8) -Article.create!(name: 'Cashewnoten', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'bio', - availability: true, price: 0.4444E2, tax: 6.0, deposit: 0.0, unit_quantity: 22, order_number: ':b936051') -Article.create!(name: 'Hazel wit', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'bio', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':9e3f85b') -Article.create!(name: 'Hazel bruin', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'bio', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':d278041') -Article.create!(name: 'Amandel Bruin Spaans', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.999E1, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':0b51a8d') -Article.create!(name: 'Paranoten (bio)', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 20, order_number: ':01e59e3') -Article.create!(name: 'Bio walnoten light halfjes', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':7ff8587') -Article.create!(name: 'Pijnboompitten', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':aa88d9f') -Article.create!(name: 'Pompoen', supplier_id: 4, article_category_id: 13, unit: 'kg', note: 'bio', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':e63069b') -Article.create!(name: 'Zonnepitten (bio)', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.999E1, tax: 6.0, deposit: 0.0, unit_quantity: 25, order_number: ':0428388') -Article.create!(name: 'Amandel Wit Spaans', supplier_id: 4, article_category_id: 13, unit: 'kg', - note: 'bio', availability: true, price: 0.66666E3, tax: 6.0, deposit: 0.0, unit_quantity: 10, order_number: ':a8f0734') -Article.create!(name: 'Cashew', supplier_id: 4, article_category_id: 13, unit: 'kg', availability: true, - price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':1d26958') -Article.create!(name: 'Amandelen geblancheerd', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':31439e2') -Article.create!(name: 'Amandelen naturel', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':9c49374') -Article.create!(name: 'Walnoot ELH hafjes', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.4444E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':92907d1') -Article.create!(name: 'Walnoot ELP stukjes', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':395640e') -Article.create!(name: 'Paranoten', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':710acbb') -Article.create!(name: 'Macadamia Stijl 0', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':bbaf40b') -Article.create!(name: 'Pecan', supplier_id: 4, article_category_id: 13, unit: 'kg', availability: true, - price: 0.55555E3, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':7958183') -Article.create!(name: 'Hazelnoten naturel', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.6666E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':50392a8') -Article.create!(name: 'Hazelnoten geblancheerd', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':4fe6525') -Article.create!(name: 'Gemengde Noten', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.333E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c051b22') -Article.create!(name: "Pinda's", supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.777E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':f507577') -Article.create!(name: "Vliespinda's klein", supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.8888E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':ce563bb') -Article.create!(name: 'Medjoul dadels', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.3333E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':8232061') -Article.create!(name: 'Turkse Abrikozen ongezwaveld', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':185084f') -Article.create!(name: 'Turkse Abrikozen gezwaveld', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':2b2fb20') -Article.create!(name: 'Spaanse Vijgen', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.444E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':82590b1') -Article.create!(name: 'Turkse Vijgen', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.555E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':cabeeb6') -Article.create!(name: 'Zure Abrikozen Zuid Afrika', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':2ac18b7') -Article.create!(name: 'Blauwe rozijnen Flames', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':16bfa75') -Article.create!(name: 'Gele Rozijnen', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':1c59324') -Article.create!(name: 'Rode Rozijnen', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.1111E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c3fcd84') -Article.create!(name: 'Cranberries heel', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.222E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':921c168') -Article.create!(name: 'Gedroogde Appeltjes', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.555E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':902c67b') -Article.create!(name: 'Gedroogde pruimen zonder pit', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.222E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':a847f91') -Article.create!(name: 'Pompoenpitten', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.111E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':535645f') -Article.create!(name: 'Zonnenbloepitten', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.666E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':4ab9a83') -Article.create!(name: 'Lijnzaad', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55E0, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':04be223') -Article.create!(name: 'Maanzaad', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.7777E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':ec5b2b9') -Article.create!(name: 'Pijnboompitten medium china', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':0e5b0b8') -Article.create!(name: 'Goji bessen', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':d52ee00') -Article.create!(name: 'Mulberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.5555E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':5f46bd5') -Article.create!(name: 'Gepelde Hennep', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.5555E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':c39165b') -Article.create!(name: 'Incaberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.888E1, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':8d44fe7') -Article.create!(name: 'Blueberries', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.2222E2, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':9a95422') -Article.create!(name: 'Chia zaad', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55555E3, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':416d57b') -Article.create!(name: 'Cocos Rasp', supplier_id: 4, article_category_id: 13, unit: 'kg', - availability: true, price: 0.55E0, tax: 6.0, deposit: 0.0, unit_quantity: 1, order_number: ':b3f65e4') - -## Members & groups - -User.create!(id: 1, nick: 'admin', password: 'secret', first_name: 'Anton', last_name: 'Administrator', - email: 'admin@foo.test', created_on: 'Wed, 15 Jan 2014 16:15:33 UTC +00:00') -User.create!(id: 2, nick: 'john', password: 'secret', first_name: 'John', last_name: 'Doe', - email: 'john@doe.test', created_on: 'Sun, 19 Jan 2014 17:38:22 UTC +00:00') -User.create!(id: 3, nick: 'peter', password: 'secret', first_name: 'Peter', last_name: 'Pieterssen', - email: 'peter@pieterssen.test', created_on: 'Sat, 25 Jan 2014 20:20:36 UTC +00:00') -User.create!(id: 4, nick: 'jan', password: 'secret', first_name: 'Jan', last_name: 'Klaassen', - email: 'jan@klaassen.test', created_on: 'Mon, 27 Jan 2014 16:22:14 UTC +00:00') -User.create!(id: 5, nick: 'mary', password: 'secret', first_name: 'Marie', last_name: 'Klaassen', - email: 'mary@klaassen.test', created_on: 'Mon, 03 Feb 2014 11:47:17 UTC +00:00') - -Workgroup.create!(id: 1, name: 'Admins', description: 'Beheerders', account_balance: 0.0, - created_on: 'Wed, 15 Jan 2014 16:15:33 UTC +00:00', role_admin: true, role_suppliers: true, role_article_meta: true, role_finance: true, role_orders: true, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Workgroup.create!(id: 2, name: 'Financiën', account_balance: 0.0, - created_on: 'Sun, 19 Jan 2014 17:40:03 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: false, role_finance: true, role_orders: false, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Workgroup.create!(id: 3, name: 'Bestellen', account_balance: 0.0, - created_on: 'Thu, 20 Feb 2014 14:44:47 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: true, role_finance: false, role_orders: true, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Workgroup.create!(id: 4, name: 'Assortiment', account_balance: 0.0, - created_on: 'Wed, 09 Apr 2014 12:24:55 UTC +00:00', role_admin: false, role_suppliers: true, role_article_meta: true, role_finance: false, role_orders: false, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Ordergroup.create!(id: 5, name: 'Admin Administrator', account_balance: 0.0, - created_on: 'Sat, 18 Jan 2014 00:38:48 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: false, role_finance: false, role_orders: false, stats: { jobs_size: 0, orders_sum: 1021.74 }, next_weekly_tasks_number: 8, ignore_apple_restriction: true) -Ordergroup.create!(id: 6, name: "Peter's huis", account_balance: -0.35E2, - created_on: 'Sat, 25 Jan 2014 20:20:37 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: false, role_finance: false, role_orders: false, contact_person: 'Piet Pieterssen', stats: { jobs_size: 0, orders_sum: 60.96 }, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Ordergroup.create!(id: 7, name: 'Jan Klaassen', account_balance: -0.35E2, - created_on: 'Mon, 27 Jan 2014 16:22:14 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: false, role_finance: false, role_orders: false, contact_person: 'Jan Klaassen', stats: { jobs_size: 0, orders_sum: 0 }, next_weekly_tasks_number: 8, ignore_apple_restriction: false) -Ordergroup.create!(id: 8, name: 'John Doe', account_balance: 0.90E2, - created_on: 'Wed, 09 Apr 2014 12:23:29 UTC +00:00', role_admin: false, role_suppliers: false, role_article_meta: false, role_finance: false, role_orders: false, contact_person: 'John Doe', stats: { jobs_size: 0, orders_sum: 0 }, next_weekly_tasks_number: 8, ignore_apple_restriction: false) - -Membership.create!(group_id: 1, user_id: 1) -Membership.create!(group_id: 5, user_id: 1) -Membership.create!(group_id: 2, user_id: 2) -Membership.create!(group_id: 8, user_id: 2) -Membership.create!(group_id: 6, user_id: 3) -Membership.create!(group_id: 7, user_id: 4) -Membership.create!(group_id: 8, user_id: 4) -Membership.create!(group_id: 3, user_id: 4) -Membership.create!(group_id: 7, user_id: 5) -Membership.create!(group_id: 3, user_id: 5) -Membership.create!(group_id: 4, user_id: 5) - -## Orders & OrderArticles - -seed_order(supplier_id: 1, starts: 2.days.ago, ends: 5.days.from_now) -seed_order(supplier_id: 3, starts: 2.days.ago, ends: 5.days.from_now) -seed_order(supplier_id: 2, starts: 2.days.ago, ends: 4.days.from_now) - -## GroupOrders & such - -seed_group_orders - -## Finances - -FinancialTransactionType.create!(id: 1, name: 'Foodcoop', financial_transaction_class_id: 1) - -FinancialTransaction.create!(id: 1, ordergroup_id: 5, amount: -0.35E2, - note: 'Membership fee for ordergroup', user_id: 1, created_on: 'Sat, 18 Jan 2014 00:38:48 UTC +00:00', financial_transaction_type_id: 1) -FinancialTransaction.create!(id: 3, ordergroup_id: 6, amount: -0.35E2, - note: 'Membership fee for ordergroup', user_id: 1, created_on: 'Sat, 25 Jan 2014 20:20:37 UTC +00:00', financial_transaction_type_id: 1) -FinancialTransaction.create!(id: 4, ordergroup_id: 7, amount: -0.35E2, - note: 'Membership fee for ordergroup', user_id: 1, created_on: 'Mon, 27 Jan 2014 16:22:14 UTC +00:00', financial_transaction_type_id: 1) -FinancialTransaction.create!(id: 5, ordergroup_id: 5, amount: 0.35E2, note: 'payment', user_id: 2, - created_on: 'Wed, 05 Feb 2014 16:49:24 UTC +00:00', financial_transaction_type_id: 1) -FinancialTransaction.create!(id: 6, ordergroup_id: 8, amount: 0.90E2, note: 'Bank transfer', user_id: 2, - created_on: 'Mon, 17 Feb 2014 16:19:34 UTC +00:00', financial_transaction_type_id: 1) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index b0a325db4..d0a9e22ae 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -36,6 +36,8 @@ services: - MYSQL_DATABASE=development volumes: - mariadb:/var/lib/mysql + ports: + - "3306:3306" phpmyadmin: image: phpmyadmin/phpmyadmin diff --git a/lib/article_units_lib.rb b/lib/article_units_lib.rb new file mode 100644 index 000000000..481a74b1a --- /dev/null +++ b/lib/article_units_lib.rb @@ -0,0 +1,193 @@ +class ArticleUnitsLib + DEFAULT_PIECE_UNIT_CODES = %w[PTN STC XCU XCN XSH X43 XST XOK XVA XBX XBH XBE XCX XBJ XUN XOS XDH XBA XFI XBO XBQ XFB XFT XJR XGR XOW X8B XCV XWA XEI XJT XGY XJY XBD XCR XAI XPA XBK XBI XOV XNT XPK XPC XPX X5M XPR XEC X6H X44 XBR XCW XBT XSA XBM XSX XDN XAE XSC XLU X5L XPP XPU XBG XP2 XCK XPT XGI XTU] + DEFAULT_METRIC_SCALAR_UNIT_CODES = %w[KGM HGM DJ GRM LTR DLT CLT MLT] + DEFAULT_IMPERIAL_SCALAR_UNIT_CODES = %w[LBR ONZ GLL QTI PTI] + + @un_ece_20_units = YAML.safe_load(ERB.new(File.read(File.expand_path( + 'config/units-of-measure/un-ece-20-remastered.yml', Rails.root + ))).result) + @un_ece_21_units = YAML.safe_load(ERB.new(File.read(File.expand_path('config/units-of-measure/un-ece-21.yml', + Rails.root))).result) + + def self.untranslated_units + return @untranslated_units unless @untranslated_units.nil? + + options = {} + + @un_ece_20_units.each do |unit| + code = unit['CommonCode'] + base_unit = unit['conversion']['base_units'].nil? ? nil : unit['conversion']['base_units'][0] + options[code] = + { name: unit['Name'], description: unit['Description'], baseUnit: base_unit, + conversionFactor: unit['conversion']['factor'], symbol: unit['Symbol'] } + end + + @un_ece_21_units.each do |unit| + code = 'X' + unit['Code'] + name = unit['Name'] + name[0] = name[0].downcase + + options[code] = + { name: name, description: unit['Description'], baseUnit: nil, conversionFactor: nil, symbol: unit['Symbol'] } + end + + options.each do |code, option| + option[:translation_available] = !ArticleUnitsLib.get_translated_name_for_code(code, default_nil: true).nil? + end + + @untranslated_units = options + end + + def self.unit_translations + @unit_translations = {} if @unit_translations.nil? + unit_translations_cached_in_current_locale = @unit_translations[I18n.locale] + return unit_translations_cached_in_current_locale unless unit_translations_cached_in_current_locale.nil? + + @unit_translations[I18n.locale] = YAML.safe_load(ERB.new(File.read(File.expand_path( + "config/units-of-measure/locales/unece_#{I18n.locale}.yml", Rails.root + ))).result) || {} + end + + def self.units + @units = {} if @units.nil? + units_cached_in_current_locale = @units[I18n.locale] + return units_cached_in_current_locale unless @units_cached_in_current_locale.nil? + + @units[I18n.locale] = untranslated_units.to_h do |code, untranslated_unit| + translated_name = ArticleUnitsLib.get_translated_name_for_code(code, default_nil: true) + unit = untranslated_unit.clone + unit[:name] = translated_name || unit[:name] + unit[:untranslated] = translated_name.nil? + unit[:symbol] = ArticleUnitsLib.get_translated_symbol_for_code(code) + unit[:aliases] = ArticleUnitsLib.get_translated_aliases_for_code(code) + + [code, unit] + end + end + + def self.unit_is_si_convertible(code) + !units.to_h[code]&.dig(:conversionFactor).nil? + end + + def self.human_readable_unit(unit_code) + unit = units.to_h[unit_code] + unit[:symbol] || unit[:name] + end + + def self.get_translated_name_for_code(code, default_nil: false) + return nil if code.blank? + + unit_translations&.dig('unece_units')&.dig(code)&.dig('name') || (default_nil ? nil : untranslated_units[code][:name]) + end + + def self.get_translated_symbol_for_code(code) + return nil if code.blank? + + unit_translations&.dig('unece_units')&.dig(code)&.dig('symbols')&.dig(0) || untranslated_units[code][:symbol] + end + + def self.get_translated_aliases_for_code(code) + return nil if code.blank? + + unit_translations&.dig('unece_units')&.dig(code)&.dig('aliases') + end + + def self.get_code_for_unit_name(name) + return nil if name.blank? + + translation = unit_translations&.dig('unece_units')&.find do |_code, translations| + translations['name'] == name + end + + return translation[0] unless translation.nil? + + matching_unit = units.find do |_code, unit| + unit[:name] == name + end + + matching_unit[0] + end + + def self.convert_old_unit(old_compound_unit_str, unit_quantity) + return nil if old_compound_unit_str.nil? + + md = old_compound_unit_str.match(/([0-9]*)x(.*)/) + old_compound_unit_str = md[2] if !md.nil? && md[1].to_f == unit_quantity + + md = old_compound_unit_str.match(%r{^\s*([0-9][0-9,./]*)?\s*([A-Za-z\u00C0-\u017F.]+)\s*$}) + return nil if md.nil? + + unit = get_unit_from_old_str(md[2]) + return nil if unit.nil? + + quantity = get_quantity_from_old_str(md[1]) + + if quantity == 1 && unit_quantity == 1 + { + supplier_order_unit: unit, + first_ratio: nil, + group_order_granularity: 1.0, + group_order_unit: unit + } + else + supplier_order_unit = unit.starts_with?('X') && unit != 'XPK' ? 'XPK' : 'XPP' + { + supplier_order_unit: supplier_order_unit, + first_ratio: { + quantity: quantity * unit_quantity, + unit: unit + }, + group_order_granularity: unit_quantity > 1 ? quantity : 1.0, + group_order_unit: unit_quantity > 1 ? unit : supplier_order_unit + } + end + end + + def self.get_quantity_from_old_str(quantity_str) + return 1 if quantity_str.nil? + + quantity_str = quantity_str + .gsub(',', '.') + .gsub(' ', '') + + division_parts = quantity_str.split('/').map(&:to_f) + + if division_parts.length == 2 + division_parts[0] / division_parts[1] + else + quantity_str.to_f + end + end + + def self.get_unit_from_old_str(old_unit_str) + unit_str = old_unit_str.strip.downcase + units = ArticleUnitsLib.untranslated_units + .sort { |a, b| sort_by_translation_state(a[1], b[1]) } + matching_unit_arr = units.select { |key, unit| matches_unit(key, unit, unit_str) } + .to_a + return nil if matching_unit_arr.empty? + + matching_unit_arr[0][0] + end + + def self.sort_by_translation_state(unit_a, unit_b) + return -1 if unit_a[:translation_available] && !unit_b[:translation_available] + return 1 if unit_b[:translation_available] && !unit_a[:translation_available] + + 0 + end + + def self.matches_unit(unit_code, unit, unit_str) + return true if unit[:symbol] == unit_str + + translation_data = unit_translations&.dig('unece_units')&.dig(unit_code) + + return true if translation_data&.dig('symbols')&.include?(unit_str) + + name = translation_data&.dig('name')&.downcase + return true if !name.nil? && name == unit_str + + aliases = translation_data&.dig('aliases')&.map(&:strip)&.map(&:downcase) + !aliases.nil? && aliases.any? { |a| a == unit_str || "#{a}." == unit_str } + end +end diff --git a/lib/tasks/foodsoft.rake b/lib/tasks/foodsoft.rake index 872c7d6d0..d2a64d01a 100644 --- a/lib/tasks/foodsoft.rake +++ b/lib/tasks/foodsoft.rake @@ -1,6 +1,6 @@ # put in here all foodsoft tasks # => :environment loads the environment an gives easy access to the application -namespace :foodsoft do # rubocop:disable Metrics/BlockLength +namespace :foodsoft do desc 'Finish ended orders' task finish_ended_orders: :environment do Order.finish_ended! diff --git a/lib/tasks/temp_export_supplier.rake b/lib/tasks/temp_export_supplier.rake new file mode 100644 index 000000000..f08267687 --- /dev/null +++ b/lib/tasks/temp_export_supplier.rake @@ -0,0 +1,33 @@ +namespace :temp_supplier do + task export: :environment do + supplier_id = ENV['SUPPLIER_ID']&.to_i + raise 'Missing supplier id' if supplier_id.nil? + + s = Supplier.find_by_id(supplier_id) + article_hashes = s.articles.map do |a| + article_attributes = a.attributes.delete_if { |key| %w[quantity type deleted_at shared_updated_on].include?(key) } + latest_version_attributes = a.latest_article_version.attributes.delete_if do |key| + %w[article_id id].include?(key) + end + aur = a.article_unit_ratios.map do |ratio| + attributes = ratio.attributes + attributes.delete_if { |key| %w[id sort].include?(key) } + attributes + end + + cat = ArticleCategory.find_by_id(latest_version_attributes['article_category_id']) + latest_version_attributes['article_category'] = cat.attributes.delete('id') + latest_version_attributes.delete('article_category_id') + + article_attributes.merge(latest_version_attributes).merge(article_unit_ratios: aur) + end + + puts JSON.pretty_generate({ + api_version: 1, + data: { + changed_after: Time.now, + articles: article_hashes + } + }) + end +end diff --git a/lib/tasks/units.rake b/lib/tasks/units.rake new file mode 100644 index 000000000..3dde517ca --- /dev/null +++ b/lib/tasks/units.rake @@ -0,0 +1,136 @@ +namespace :units do + task clean_unece20_source: :environment do + base_unit_entries = [] + + un_ece_20_units = YAML.safe_load(ERB.new(File.read(File.expand_path('config/units-of-measure/un-ece-20.yml', + Rails.root))).result) + re = /^(?:([, 0-9]*)(?: x )!?)?([, 0-9⁰-⁹⁻¹²³]*)?(.*)?$/ + un_ece_20_units.each do |unit| + fixed_conversion_factor = fix_conversion_factor(unit['ConversionFactor']) + md = fixed_conversion_factor.match(re) + multiplier = md[1] + potency = md[2] + base_unit = md[3] + + multiplier&.strip! + potency&.strip! + base_unit&.strip! + + if multiplier.blank? && (!potency.nil? && !/[⁰-⁹⁻¹²³]+/.match(potency)) + multiplier = potency + potency = '' + end + + multiplier&.gsub!(',', '.') + multiplier&.gsub!(' ', '') + multiplier = multiplier.blank? ? 1 : BigDecimal(multiplier) + + unit['conversion'] = {} + unit['conversion']['unit'] = base_unit + + unit['Symbol'] = '' if unit['Symbol'] == unit['CommonCode'] + + power_of_ten = potency.match(/^10 *?([⁰-⁹⁻¹²³]+)$/)&.[](1) + power_of_ten = superscript_to_number(power_of_ten) unless power_of_ten.nil? + + base_unit_multiplier = multiplier + base_unit_multiplier *= (10**power_of_ten) unless power_of_ten.nil? + unit['conversion']['factor'] = base_unit_multiplier.to_s.to_f + is_base_unit = base_unit.present? && potency.blank? && multiplier == 1 + + base_unit_entries << unit if is_base_unit + end + + # rubocop:disable Style/CombinableLoops + un_ece_20_units.each do |unit| + next if unit['conversion']['unit'].blank? + + base_units = base_unit_entries.select { |entry| entry['conversion']['unit'] == unit['conversion']['unit'] } + unit['conversion']['base_units'] = base_units.pluck('CommonCode') + end + + un_ece_20_units.each do |unit| + unit['conversion'].delete('unit') + end + # rubocop:enable Style/CombinableLoops + + result = "# This file has been autogenerated by `rake units:clean_unece20_source`\n#{un_ece_20_units.to_yaml}" + File.write(File.expand_path('config/units-of-measure/un-ece-20-remastered.yml', Rails.root), result) + end + + task build_i18n_from_csv: :environment do + translations = { de: {}, en: {} } + csv_options = { csv_options: { col_sep: ',' } } + SpreadsheetFile.parse 'config/units-of-measure/translations_piece.csv', csv_options do |row, index| + next if index == 0 + + code = row[0] + next if code.nil? # empty csv row + + translation_en = { name: row[2].strip } + translation_en[:abbreviation] = row[3].strip if row[3].present? + translation_en[:aliases] = row[4].split(', ') if row[4].present? + translations[:en][code] = translation_en + + translation_de = { name: row[5].strip } + translation_de[:abbreviation] = row[6].strip if row[6].present? + translation_de[:aliases] = row[7].split(', ') if row[7].present? + translations[:de][code] = translation_de + end + + %i[en de].each do |locale| + SpreadsheetFile.parse "config/units-of-measure/translations_scalar-#{locale}.csv", csv_options do |row, index| + next if index == 0 + + code = row[0] + next if code.nil? # empty csv row + + translation = { name: row[2].strip, long_name: row[1].strip } + translation[:symbols] = [] + translation[:symbols] << row[3].strip if row[3].present? + alternate_symbols = row[4]&.strip + if alternate_symbols.present? + alternate_symbols.split(', ').each do |symbol| + translation[:symbols] << symbol.strip + end + end + translation[:aliases] = row[5].split(', ') if row[5].present? + translations[locale][code] = translation + end + result = "# This file has been autogenerated by `rake units:build_i18n_from_csv`\n#{{ unece_units: translations[locale] }.deep_stringify_keys.to_yaml}" + File.write(File.expand_path("config/units-of-measure/locales/unece_#{locale}.yml", Rails.root), result) + end + end +end + +def superscript_hash + { + '⁻' => '-', '⁰' => '0', '¹' => '1', '²' => '2', '³' => '3', '⁴' => '4', '⁵' => '5', '⁶' => '6', '⁷' => '7', '⁸' => '8', '⁹' => '9' + } +end + +# I know this is stupid, but I couldn't find a default ruby/rails method for this and wouldn't be +# bothered to write a nicer unicode mapper for these few characters: +def superscript_to_number(str) + str = str.chars.map { |c| superscript_hash[c] }.join + + BigDecimal(str) unless str == '' +end + +def number_to_superscript(str) + conversion_hash = superscript_hash.invert + str.chars.map { |c| conversion_hash[c] }.join +end + +def fix_conversion_factor(conversion_factor) + # m2 -> m²: + conversion_factor = conversion_factor.gsub(%r{(\s|^|/)m2(\s|$|/)}, '\1m²\2') + + # m3 -> m³ + conversion_factor = conversion_factor.gsub(%r{(\s|^|/)m3(\s|$|/)}, '\1m³\2') + + # 10-15 m³ -> 10⁻¹⁵ m³: + conversion_factor.gsub(%r{(\s|^|/)10 ?(- ?[0-9]+)(\s|$|/)}) do + Regexp.last_match[1] + '10' + number_to_superscript(Regexp.last_match[2]) + Regexp.last_match[3] + end +end diff --git a/plugins/current_orders/app/controllers/current_orders/articles_controller.rb b/plugins/current_orders/app/controllers/current_orders/articles_controller.rb index 51111f3fa..503f07574 100644 --- a/plugins/current_orders/app/controllers/current_orders/articles_controller.rb +++ b/plugins/current_orders/app/controllers/current_orders/articles_controller.rb @@ -33,7 +33,7 @@ def find_order_and_order_article @order_articles = @order.order_articles end @q = OrderArticle.ransack(params[:q]) - @order_articles = @order_articles.ordered.merge(@q.result).includes(:article, :article_price) + @order_articles = @order_articles.ordered.merge(@q.result).includes(:article, :article_version) @order_article = @order_articles.where(id: params[:id]).first end diff --git a/plugins/current_orders/app/controllers/current_orders/group_orders_controller.rb b/plugins/current_orders/app/controllers/current_orders/group_orders_controller.rb index 945bfd302..20f6e1722 100644 --- a/plugins/current_orders/app/controllers/current_orders/group_orders_controller.rb +++ b/plugins/current_orders/app/controllers/current_orders/group_orders_controller.rb @@ -9,7 +9,7 @@ def index .where(group_orders: { order_id: @order_ids, ordergroup_id: @ordergroup.id }).ordered @articles_grouped_by_category = @goas.includes(order_article: { article: :article_category }) .order('articles.name') - .group_by { |a| a.order_article.article.article_category.name } + .group_by { |a| a.order_article.article_version.article_category.name } .sort { |a, b| a[0] <=> b[0] } end diff --git a/plugins/current_orders/app/controllers/current_orders/ordergroups_controller.rb b/plugins/current_orders/app/controllers/current_orders/ordergroups_controller.rb index 94390a0ab..62d5d36ef 100644 --- a/plugins/current_orders/app/controllers/current_orders/ordergroups_controller.rb +++ b/plugins/current_orders/app/controllers/current_orders/ordergroups_controller.rb @@ -36,13 +36,12 @@ def find_group_orders @ordergroup = Ordergroup.find(params[:id]) unless params[:id].nil? return if @ordergroup.nil? - @goas = GroupOrderArticle.includes(:group_order, order_article: %i[article article_price]) - .where(group_orders: { order_id: @order_ids, - ordergroup_id: @ordergroup.id }).ordered.all + @goas = GroupOrderArticle.includes(:group_order, order_article: %i[article article_version]) + .where(group_orders: { order_id: @order_ids, ordergroup_id: @ordergroup.id }).ordered.all end helper_method \ def articles_for_adding - OrderArticle.includes(:article, :article_price).where(order_id: @order_ids) + OrderArticle.includes(:article, :article_version).where(order_id: @order_ids) end end diff --git a/plugins/current_orders/app/documents/multiple_orders_by_articles.rb b/plugins/current_orders/app/documents/multiple_orders_by_articles.rb index 9ea55020d..43966e3b3 100644 --- a/plugins/current_orders/app/documents/multiple_orders_by_articles.rb +++ b/plugins/current_orders/app/documents/multiple_orders_by_articles.rb @@ -40,8 +40,8 @@ def body sum[:quantity], nil] # number_to_currency(sum[:price])] - text "#{order_article.article.name} " + - "(#{order_article.article.unit}; #{number_to_currency order_article.price.fc_price}; " + + text "#{order_article.article_version.name} " + + "(#{order_article.article_version.unit}; #{number_to_currency order_article.article_version.fc_price}; " + units_history_line(order_article, plain: true) + ')', size: fontsize(10), inline_format: true table rows, cell_style: { size: fontsize(8), overflow: :shrink_to_fit } do |table| @@ -76,7 +76,7 @@ def order_articles OrderArticle.where(order_id: order).ordered .includes(:article).references(:article) .reorder('order_articles.order_id, articles.name') - .preload(:article_price) # preload not join, just in case it went missing + .preload(:article_version) # preload not join, just in case it went missing .preload(:order, group_order_articles: { group_order: :ordergroup }) end diff --git a/plugins/current_orders/app/documents/multiple_orders_by_groups.rb b/plugins/current_orders/app/documents/multiple_orders_by_groups.rb index 9c4bdf535..866f788dd 100644 --- a/plugins/current_orders/app/documents/multiple_orders_by_groups.rb +++ b/plugins/current_orders/app/documents/multiple_orders_by_groups.rb @@ -28,18 +28,18 @@ def body has_tolerance = false each_group_order_article_for(ordergroup) do |goa| - has_tolerance = true if goa.order_article.price.unit_quantity > 1 - price = goa.order_article.price.fc_price + has_tolerance = true if goa.order_article.article_version.unit_quantity > 1 + price = goa.order_article.article_version.fc_price sub_total = goa.total_price total += sub_total - rows << [goa.order_article.article.name, + rows << [goa.order_article.article_version.name, goa.group_order.order.name.truncate(10, omission: ''), number_to_currency(price), - goa.order_article.article.unit, + goa.order_article.article_version.unit, goa.tolerance > 0 ? "#{goa.quantity} + #{goa.tolerance}" : goa.quantity, group_order_article_result(goa), number_to_currency(sub_total), - goa.order_article.price.unit_quantity] + goa.order_article.article_version.unit_quantity] dimrows << rows.length if goa.result == 0 end next if rows.length == 0 @@ -121,7 +121,7 @@ def each_ordergroup(&block) .where(group_orders: { ordergroup_id: ordergroups.map(&:id) }) .order('group_orders.order_id, group_order_articles.id') .preload(group_orders: { order: :supplier }) - .preload(order_article: %i[article article_price order]) + .preload(order_article: %i[article article_version order]) ordergroups.each(&block) end end diff --git a/plugins/current_orders/app/views/current_orders/articles/_article_info.html.haml b/plugins/current_orders/app/views/current_orders/articles/_article_info.html.haml index 6b2f0f4c7..a901e3a8c 100644 --- a/plugins/current_orders/app/views/current_orders/articles/_article_info.html.haml +++ b/plugins/current_orders/app/views/current_orders/articles/_article_info.html.haml @@ -1,22 +1,22 @@ #article_info %h2{style: 'margin-bottom: 0'} - = t('current_orders.articles.show.title', name: order_article.article.name) - %span.normal= order_article.article.unit + = t('current_orders.articles.show.title', name: order_article.article_version.name) + %span.normal= order_article.article_version.unit -# @todo unduplicate from group_orders's order_article_info %p - - if order_article.article.manufacturer.blank? + - if order_article.article_version.manufacturer.blank? = raw t '.supplied_by', supplier: content_tag(:em, supplier_link(order_article.order)) - - elsif order_article.article.supplier && order_article.article.supplier.name == order_article.article.manufacturer + - elsif order_article.article_version.article.supplier && order_article.article_version.article.supplier.name == order_article.article_version.manufacturer = raw t '.supplied_and_made_by', manufacturer: content_tag(:em, supplier_link(order_article.order)) - else - = raw t '.supplied_by_made_by', supplier: content_tag(:em, supplier_link(order_article.order)), manufacturer: content_tag(:em, order_article.article.manufacturer) - - unless order_article.article.origin.blank? - = raw t '.origin_in', origin: content_tag(:em, order_article.article.origin) + = raw t '.supplied_by_made_by', supplier: content_tag(:em, supplier_link(order_article.order)), manufacturer: content_tag(:em, order_article.article_version.manufacturer) + - unless order_article.article_version.origin.blank? + = raw t '.origin_in', origin: content_tag(:em, order_article.article_version.origin) - pkg_info = pkg_helper(order_article.price) = ", #{pkg_info}".html_safe unless pkg_info.blank? = ", " = Article.human_attribute_name(:fc_price_short) + ": " - = number_to_currency(order_article.price.fc_price) - = t '.unit', unit: order_article.article.unit + = number_to_currency(order_article.article_version.fc_price) + = t '.unit', unit: order_article.article_version.unit diff --git a/plugins/current_orders/app/views/current_orders/articles/_articles.html.haml b/plugins/current_orders/app/views/current_orders/articles/_articles.html.haml index ab00d38be..ace8b3c68 100644 --- a/plugins/current_orders/app/views/current_orders/articles/_articles.html.haml +++ b/plugins/current_orders/app/views/current_orders/articles/_articles.html.haml @@ -1,4 +1,4 @@ - @order_articles.includes(:order => :supplier).reorder('suppliers.name, articles.article_category_id, articles.name').group_by {|oa| oa.order.name}.each do |name, articles| %li.nav-header= name - articles.each do |oa| - %li= link_to oa.article.name, current_orders_articles_path(order_id: oa.order_id, id: oa.id, anchor: 'order_article'), remote: true + %li= link_to oa.article_version.name, current_orders_articles_path(order_id: oa.order_id, id: oa.id, anchor: 'order_article'), remote: true diff --git a/plugins/current_orders/app/views/current_orders/articles/_ordergroups.html.haml b/plugins/current_orders/app/views/current_orders/articles/_ordergroups.html.haml index 908b7571c..03194ef28 100644 --- a/plugins/current_orders/app/views/current_orders/articles/_ordergroups.html.haml +++ b/plugins/current_orders/app/views/current_orders/articles/_ordergroups.html.haml @@ -30,5 +30,5 @@ %td %td %td.center - %span.units_delta{data: {'quantity-expected' => order_article.units * order_article.price.unit_quantity}} + %span.units_delta{data: {'quantity-expected' => order_article.units * order_article.article_version.unit_quantity}} %td diff --git a/plugins/current_orders/app/views/current_orders/articles/show.html.haml b/plugins/current_orders/app/views/current_orders/articles/show.html.haml index e6d600f8a..0c77180cd 100644 --- a/plugins/current_orders/app/views/current_orders/articles/show.html.haml +++ b/plugins/current_orders/app/views/current_orders/articles/show.html.haml @@ -1,3 +1,3 @@ -- title t('.title', name: @order_article.article.name), false +- title t('.title', name: @order_article.article_version.name), false = render 'form' diff --git a/plugins/current_orders/app/views/current_orders/group_orders/_result.html.haml b/plugins/current_orders/app/views/current_orders/group_orders/_result.html.haml index 7d247d7d2..799f6dfeb 100644 --- a/plugins/current_orders/app/views/current_orders/group_orders/_result.html.haml +++ b/plugins/current_orders/app/views/current_orders/group_orders/_result.html.haml @@ -30,21 +30,21 @@ - group_order_sum += r[:sub_total] %tr{class: cycle('even', 'odd', name: 'articles') + " order-article " + order_article_class_name(r[:quantity], r[:tolerance], r[:result])} -# article_info is present in foodcoop-adam only - %td.name{style: "width:40%", title: (article_info_title(oa.article) rescue nil)} - = article_info_icon oa.article rescue nil - = oa.article.name + %td.name{style: "width:40%", title: (article_info_title(oa.article_version) rescue nil)} + = article_info_icon oa.article_version rescue nil + = oa.article_version.name %td - = oa.article.unit + = oa.article_version.unit %span{style: 'opacity: 0.4; margin-left: 1em;'}= pkg_helper(oa.price, soft_uq: true) - %td= number_to_currency oa.price.fc_price + %td= number_to_currency oa.article_version.fc_price %td = r[:quantity] - = "+ #{r[:tolerance]}" if oa.price.unit_quantity > 1 + = "+ #{r[:tolerance]}" if oa.article_version.unit_quantity > 1 %td= r[:result] > 0 ? r[:result] : "0" %td= number_to_currency(r[:sub_total]) - - unless oa.article.note.blank? + - unless oa.article_version.note.blank? %tr{id: "note_#{oa.id}", class: "note even", style: "display:none"} - %td{colspan: "6"}=h oa.article.note + %td{colspan: "6"}=h oa.article_version.note %tr{class: cycle('even', 'odd', name: 'articles')} %th{colspan: "5"}= heading_helper GroupOrder, :price %th= number_to_currency(group_order_sum) diff --git a/plugins/current_orders/app/views/current_orders/ordergroups/_article.html.haml b/plugins/current_orders/app/views/current_orders/ordergroups/_article.html.haml index 4659f7880..ad58d1a3c 100644 --- a/plugins/current_orders/app/views/current_orders/ordergroups/_article.html.haml +++ b/plugins/current_orders/app/views/current_orders/ordergroups/_article.html.haml @@ -1,12 +1,12 @@ -# output row %tr{:class => [cycle('even', 'odd', :name => 'articles'), if goa.result == 0 then 'unavailable' end], id: "goa_#{goa.id}"} - %td.name= goa.order_article.article.name + %td.name= goa.order_article.article_version.name %td{title: goa.order_article.order.name}= link_to goa.order_article.order.name.truncate(15), goa.order_article.order - %td= goa.order_article.article.unit + %td= goa.order_article.article_version.unit %td.center= "#{goa.quantity} + #{goa.tolerance}" %td.center.input-delta= group_order_article_edit_result(goa) %td.symbol × - %td= number_to_currency goa.order_article.price.fc_price + %td= number_to_currency goa.order_article.article_version.fc_price %td.symbol = %td.price{data: {value: goa.total_price}}= number_to_currency goa.total_price diff --git a/plugins/current_orders/app/views/current_orders/ordergroups/_articles.html.haml b/plugins/current_orders/app/views/current_orders/ordergroups/_articles.html.haml index 881baa0c7..9db7e475e 100644 --- a/plugins/current_orders/app/views/current_orders/ordergroups/_articles.html.haml +++ b/plugins/current_orders/app/views/current_orders/ordergroups/_articles.html.haml @@ -28,7 +28,7 @@ %tfoot %tr %td{colspan: 9} - - new_article_data = articles_for_select2(articles_for_adding) {|a| "#{a.article.name} (#{a.article.unit}, #{number_to_currency a.price.fc_price})"} + - new_article_data = articles_for_select2(articles_for_adding) {|a| "#{a.article.name} (#{a.article.unit}, #{number_to_currency a.article_version.fc_price})"} = form_for GroupOrderArticle.new, remote: true, html: {'data-submit-onchange' => true, style: 'margin: 0'} do |f| = f.select :order_article_id, options_for_select(new_article_data.map {|a| [a[:text], a[:id]]}), diff --git a/spec/controllers/supplier_shares_controller_spec.rb b/spec/controllers/supplier_shares_controller_spec.rb new file mode 100644 index 000000000..a658afcbb --- /dev/null +++ b/spec/controllers/supplier_shares_controller_spec.rb @@ -0,0 +1,24 @@ +require_relative '../spec_helper' + +describe SupplierSharesController do + let(:user) { create(:user, groups: [create(:workgroup, role_suppliers: true)]) } + let(:supplier) { create(:supplier) } + + before do + login user + end + + it 'share supplier' do + post_with_defaults :create, params: { supplier_id: supplier.id }, xhr: true + expect(response).to have_http_status :ok + expect(supplier.reload.external_uuid).not_to be_nil + end + + it 'unshare supplier' do + supplier.update_attribute(:external_uuid, 'something') + + delete_with_defaults :destroy, params: { supplier_id: supplier.id }, xhr: true + expect(response).to have_http_status :ok + expect(supplier.reload.external_uuid).to be_nil + end +end diff --git a/spec/factories/article.rb b/spec/factories/article.rb index 69e23d88e..ce6e6b395 100644 --- a/spec/factories/article.rb +++ b/spec/factories/article.rb @@ -2,33 +2,52 @@ FactoryBot.define do factory :_article do - unit { Faker::Unit.unit } - price { rand(0.1..26.0).round(2) } - tax { [6, 21].sample } - deposit { rand(10) < 8 ? 0 : [0.0, 0.80, 1.20, 12.00].sample } - unit_quantity { rand(5) < 3 ? 1 : rand(1..20) } - factory :article do - sequence(:name) { |n| Faker::Lorem.words(number: rand(2..4)).join(' ') + " ##{n}" } supplier - article_category - end - factory :shared_article, class: 'SharedArticle' do - sequence(:name) { |n| Faker::Lorem.words(number: rand(2..4)).join(' ') + " s##{n}" } - order_number { Faker::Lorem.characters(number: rand(1..12)) } - shared_supplier + transient do + article_version_count { 1 } + order_number { nil } + unit_quantity { nil } + unit { nil } + minimum_order_quantity { nil } + supplier_order_unit { 'XPK' } + group_order_unit { 'XPK' } + billing_unit { 'XPK' } + price_unit { 'XPK' } + article_unit_ratio_count { 1 } + end + + after(:create) do |article, evaluator| + create_list(:article_version, evaluator.article_version_count, + article: article, + order_number: evaluator.order_number, + unit_quantity: evaluator.unit_quantity, + unit: evaluator.unit, + minimum_order_quantity: evaluator.minimum_order_quantity, + supplier_order_unit: evaluator.supplier_order_unit, + group_order_unit: evaluator.group_order_unit, + billing_unit: evaluator.billing_unit, + price_unit: evaluator.price_unit, + article_unit_ratio_count: evaluator.article_unit_ratio_count) + + article.reload + end end factory :stock_article, class: 'StockArticle' do - sequence(:name) { |n| Faker::Lorem.words(number: rand(2..4)).join(' ') + " ##{n}" } - unit_quantity { 1 } supplier - article_category - end - end - factory :article_category do - sequence(:name) { |n| Faker::Lorem.characters(number: rand(2..12)) + " ##{n}" } + transient do + stock_article_version_count { 1 } + price { 1 } + end + + after(:create) do |stock_article, evaluator| + create_list(:article_version, evaluator.stock_article_version_count, article: stock_article, price: evaluator.price) + + stock_article.reload + end + end end end diff --git a/spec/factories/article_category.rb b/spec/factories/article_category.rb new file mode 100644 index 000000000..1c825e8ed --- /dev/null +++ b/spec/factories/article_category.rb @@ -0,0 +1,7 @@ +require 'factory_bot' + +FactoryBot.define do + factory :article_category do + sequence(:name) { |n| Faker::Lorem.characters(number: rand(2..12)) + " ##{n}" } + end +end diff --git a/spec/factories/article_unit.rb b/spec/factories/article_unit.rb new file mode 100644 index 000000000..70e16fefb --- /dev/null +++ b/spec/factories/article_unit.rb @@ -0,0 +1,7 @@ +require 'factory_bot' + +FactoryBot.define do + factory :article_unit do + sequence(:unit) { |n| Faker::Lorem.characters(number: rand(2..12)) + " ##{n}" } + end +end diff --git a/spec/factories/article_unit_ratio.rb b/spec/factories/article_unit_ratio.rb new file mode 100644 index 000000000..74f4539b3 --- /dev/null +++ b/spec/factories/article_unit_ratio.rb @@ -0,0 +1,10 @@ +require 'factory_bot' + +FactoryBot.define do + factory :article_unit_ratio do + unit { 'XPP' } + sort { 1 } + quantity { 1 } + article_version + end +end diff --git a/spec/factories/article_version.rb b/spec/factories/article_version.rb new file mode 100644 index 000000000..b736046b0 --- /dev/null +++ b/spec/factories/article_version.rb @@ -0,0 +1,43 @@ +require 'factory_bot' +FactoryBot.define do + factory :article_version do + sequence(:name) { |n| Faker::Lorem.words(number: rand(2..4)).join(' ') + " ##{n}" } + supplier_order_unit { 'XPK' } + group_order_unit { 'XPK' } + billing_unit { 'XPK' } + price { rand(0.1..26.0).round(2) } + price_unit { 'XPK' } + tax { [6, 21].sample } + deposit { rand(10) < 8 ? 0 : [0.0, 0.80, 1.20, 12.00].sample } + article_category + article + + transient do + article_unit_ratio_count { 1 } + unit_quantity { 1 } + unit { nil } + end + + after(:create) do |article_version, evaluator| + unless evaluator.unit_quantity.nil? + article_version.group_order_unit = 'XPP' + article_version.save + end + unless evaluator.unit.nil? + article_version.supplier_order_unit = nil + article_version.unit = evaluator.unit + article_version.save + end + build_list(:article_unit_ratio, evaluator.article_unit_ratio_count, + article_version: article_version) do |record, i| + if !evaluator.unit_quantity.nil? && i == 0 + record.quantity = evaluator.unit_quantity + record.unit = 'XPP' + end + record.sort = i + 1 + record.save + record.reload + end + end + end +end diff --git a/spec/factories/supplier.rb b/spec/factories/supplier.rb index ef592a608..78966db26 100644 --- a/spec/factories/supplier.rb +++ b/spec/factories/supplier.rb @@ -11,7 +11,6 @@ end before :create do |supplier, _evaluator| - next if supplier.instance_of?(SharedSupplier) next if supplier.supplier_category_id? supplier.supplier_category = create :supplier_category @@ -20,10 +19,10 @@ after :create do |supplier, evaluator| article_count = evaluator.article_count article_count = rand(1..99) if article_count == true - create_list(:article, article_count, supplier: supplier) + article_count.times do |index| + create(:article, supplier: supplier, order_number: index.to_s) + end end - - factory :shared_supplier, class: 'SharedSupplier' end factory :supplier_category do diff --git a/spec/fixtures/foodsoft_file_01.csv b/spec/fixtures/foodsoft_file_01.csv index 8221394b4..99e6b4d86 100644 --- a/spec/fixtures/foodsoft_file_01.csv +++ b/spec/fixtures/foodsoft_file_01.csv @@ -1,5 +1,5 @@ -status;art. nummer;productnaam;notitie;producent;herkomst;eenheid;prijs ex btw;btw (%);statiegeld;colligrootte;(reserved);(reserved);categorienaam -;29932;Walnoten (ongeroosterd);bio ◎;Het grote bomenbos;Veluwe, NL;kg;2.34;6;0;1;;;Nuts -;28391;Pijnboompitten;dem;Het warme woud;TR;100g;5.56;6;0;10;;;Nuts -;1829;Appelsap (verpakt);;Appelgaarde;DE;4x250ml;3.21;6;0.4;10;;;Drinks -;177813;Tomaten;bio;De röde hof;Best, NL;500 g;1.2;6;0;20;;;Vegetables +avail.;Order number;Name;Supplier order unit;Unit;Ratios to supplier order unit;Minimum order quantity;Billing unit;Group order granularity;Group order unit;Price (net);Price unit;VAT;Deposit;Note;Category;Origin;Manufacturer +Yes;29932;Walnoten (ongeroosterd);;kg;;;;1;;2.34;;6;0;bio ◎;Nuts;Veluwe, NL;Het grote bomenbos +Yes;28391;Pijnboompitten;;100g;10 Piece;;;1;;5.56;;6;0;dem;Nuts;TR;Het warme woud +Yes;1829;Appelsap (verpakt);;4x250ml;10 Piece;;;1;;3.21;;6;0.4;;Drinks;DE;Appelgaarde +Yes;177813;Tomaten;;500 g;20 Piece;;;1;;1.2;;6;0;bio;Vegetables;Best, NL;De röde hof diff --git a/spec/fixtures/foodsoft_file_01.ods b/spec/fixtures/foodsoft_file_01.ods index 2f8a1d8a90387564e781d3b1a263a756b2fa71f3..85a14245b9ca38966bab09ea2add8683d6bf5bef 100644 GIT binary patch literal 4388 zcmZ`-2Q*w=yB=MLnjs>HZe)x)(c1`Oj83$OK6;-)5It&?C{ZGM7$l-aFChq0)I=R2 zh9Hb?hkkzEGpGCPA)1=cRn(}VF)Vp>gIk|-1OohY+q+B20%}zYIy)H1 zXX1Km_j+?t;3`{6jGrMzO^vnxsd9b@$J6tzW2v?M31VRxYV#;hlBH`)(R->$2)=xz z`lvr6FX~tVmuoR)7H(yvoAmr=)y!uTfGgYee>jI50*Eq6voWry}K3M za=v|YWW#+??P9NKMDK3t zZsZjpgwmoYlR^Ss+oLd`e6MHf)1gR=I7}`s`yDkKOZ89KK|)wV{63~n_Xgy0F%ERO z`lus0h4ve011UJ2?;xy8Q?6_!Q3xud7m5#VOjQYoj;Jc$SU6&$f)b~HWE-Q^D}hz7 zN44|b3#ZK-uZ|<#V7RjhR*xbzi<#caTH5MhHngZ@jl)Tevb4MCn0Cc1F+BRI&#y~* zTY!V0F>bx~C@js&jw&oq`Cw`FAS`k+}>k8Rh1RTyy?>~CBFS`l$3Vrt} z<(FqUho5y=CPq5$4WP?O_Zg&<^NI}r-H2$N#_q_bx#mX8Yl{1E^de2i-QTM}=Avvb zGgHz@#bF*SM0HK-$CSPUD<{f+dJ~lNnOp87e$Sp@T9OeG+4_qBeRQbU2bs*Q$&Q0O zGYH+*u)1~G4i?HKPPpnJM-=>g=H+&eNyFhseyRzp3o)E*{R&+p@~ac22%LjID1BcTty@&W4dW1 zDRo#za9jt0zg^jLG!5OQWLOJi5T|i`CN1Gd8qqp;X6;`S7QC}A%m1FqLB41Ji+1mW zdM%7`YG$BzPkRxrwyYKfyvmRGA9#GT_E3~NCFERTjZR5+B-*cI5qP)b%sr1G+GA9_ z;smqyd!KquO@5({w3j9N^qRJ}K|9n{D{raoad?E^%mjir@qny@*?lepmDASTf1MF(jh?` zXj%M{?&ndxaH}DNg!+zI_*^$B;^j`BYiqlUM`|zir)loXPn7-lx~n=Xrvu2eW_dVh zW=0FR%6cUdN7YzE6h(ExS82OYmGr+Rsj77kSK;9;9OUN|nf(e6JQN)nxT|?zXVm$q zu%+amKwT8Ssj6+YU0@HT{$H;@m@3L|^Pb|pUp1N93?{3!%rJu1BBD(I@yQsQ2(czyPkWrtYGzQzo)K4nDo=+}%S zWdAFtqj}k^0srX=dp+;XX&$hge1j+O!_d<=t2v5%z<0}OaXjbcD{hDLvT6KyD*Ot= z@Q)gw#K(7A3V6%J`d2LFs|y%m)wBeKjDhs|HJ^wGM6#;`JH?ca#nD)JC1uD=p$`~~ z_g(EXlAFz(0SzpW?gYh|XB6qd`@0}ltwa-qE6HdDBVPz~+addXj%2BNG&6ehBv_AX z-ldit8(1&T%g^}UX|%Gtm37Q$v@A-|AhE@NdW4|)(eYwLMr(*5uRHSPxCpg8ZxOVp zl_a^}QH_<+8ZN|*M{gW_)oK^X@}nKA$3$+Ai0%e&C%tPyW#uWL1@4GEcV-%CsHhyY zX(9BWlEzD^gJZZYl%P68eiqA4zAdb%!2%@(%lzrlWY^^5?qa*tmymO19y@XQi#bNU zxeY0m6Ai)Kx?nzr;QXa}m;s4!RNOHR#ZVl)Nw zJi`K}*vi!k0;2u?>lq>BIT99`(-PEU_(XmloY1=p?_zDhhNu_7ZeMw9$0g%a97r0! zDE&PQN5u)0+t}gii~R-uNb!VaTFdyk_oO36usJ*=y53UXtWO13np(~&s9l$&G0(%i z)tby=NzCl<-4*ZwnRAujy}JFWL_%sOw^KM=fg-`Qdf;uQ@?(B|4d+g0kYY4L*A4b+ z8!-tJUuTf>Gz}G!tHZ8BB)74E9*D03j_$mg5JXtaxLA)nIBh*jz6%c&sw{7%UG1)5i`gKoL zI4Q>O$i~`FGD->Z8Va+#nEueI&8o-&XWc0iQBX4haTDNGCzR(Y>_rRx;<_@qK0%Nn zo&*)MmIry=TuH)~o8llnZhA4L2V%9nj4h^bC;Hbag_aBAi^)Uf!>!cdKu7QLpGxBC zu^QMFgM-Jhoy|K2FXKXOp$J64chJq0l2_^}IqSZGgzMz~-~`Mi=DF2ck1hkulN)(f zD~ubLF~A0kmdRYhLde-!7^$T}DTJymy0{QDQZistz4+ZFx}U|tMgH-NZ?83`gqYsf zF3f_c3Ph(~UE-)U7*X-F*R4J|wQ1h%^>ZI5o276WU~dL} z+}zunB(;=k}UMluMjCIi=Q?vwku3ym7HO=s2p-VhKkeD}KXLA(*faDRUKx~$kp zNov)U-kCW(fXI3x?(~!}=Ov=%m=yBHZF01k{oZnEGhdm6bZn~;c9rc$)T>g0aQkT-=Cn(g)s^WbqyR8ap5vbV6JA43Nf zk2xTYc>9xpddaV!ydD}Hg=I=h6*WK)iBW}h^#Rc|grPYiNn@zdn9D>^^G-UQ&XVK? zmrUe~2THmQF48ijIj=FQ-MQ0dH9I?||$#r?rHrzoI{*52xV-|@^= z1rxR2Ba2JzmMQx-4@0J}7C^Zk&rp4Z_cV^LA^A~bXux2aStnEXqTl6i*n>^^w^{z{baSVXiV{PePIu^r2QnpZu%7OY*2Ha>q9$ zUpE_1a0~ot^(DfwW@1@M`8MC`oimC0g3d^dpkr($i^zZc6_Z9_rY0f)z>?(Oeh`Va z`K_c947HPIIO*F>euh>z*>%FxXlmPIDirFcHMN6Q5~JW5%#mbG@UvjChGMtCshsSC zZ=Z7LCX$y2fuUU#c(+JXxIU4wYze*wrbNi!Cb_8sG`@rrg02t~DKu=(eckXHW^D5D zS?N^A!hmX;4kY;n23D)n2@O2(dR>)$Dv z+hPYBt?KuLn{Ge+z{BlkIJ&@kg3hq+zhkp#t*T{sE<BelFC)7~KKVpF~Mgnj7lIW6om*71Mt9`gCF<(0lO2etb5=*KTztnNPiEPbD^H$vwY zH#(S=6&N6O(%W4KbI!qW1hnm~Dn{x6mF>S#m3=8!unkBdS808wfQ`beBlKvTlX0eR z@v8@NT}&?r9fNo68p$UiRpV!HwV*YE$H{nP&2{p%rqqyB$K z{|8}o@%YEz|Bd@wn*YIdU(^Twhfx0;`1gtY10=gBD*VUu`FDuFGx<*ldfJOR$G`Jh V4?#x$dxh-c;=IWF4Z7c>{{l*T+s^<1 literal 21727 zcmeFYQ*b6s)HNF0HYc{9cw*bOZEIrNPA0bb1QXkKGO_LCpZ7oYU7U+^cP_uK>gwI7 zebK#pb=B&%6=lF7FhD?HKtQNrS;a$bxuY0CKtTSh|As*9tnAEOy&TPq935?~OpIKu z9PF9g?M)dSj9jc-7#$qV>`fg^-0aNkT^U^*oz09)T`bMaTowOcKE=_G?-n^gK>n*Z z|9q-iy4e}q8(G=9FuDGZ$>?Zr5veFIfe42O_iqWJl%%NgzqTC&1QY}Y?4K3iOUDNS z!jUZ{Dx~U}bD0aRyD0fSl5E?`q!Xy;ow|+MK=R9CU>nnCV0*?tt*Owst~^}t0+@^F zbB%}!fr*Ln8}_0R_(3(s=zRHkY)5r{%(lb3V(V_sdYC@Or;sPQY066a!w_6d>Bfo~ zhZzc-ysh8Ae!-GGP!1|s=mK;naYy8kfsW4S^UbYTJT^w0Jj|$nE&gVSu_g z!(jmME8uTDgRmt63({Ah6XZS!zM-oU1Y||5D9xaM0yK3P1gOh4>PLUSkdU+@Ruq~v1^S9@c1iQj z)u7X$D250Dm?eHQ(T_gnN_Jzx6I7Qyap@jvEdez<0+SO&@A{_3>fgd8E-p^?9COK^;BZ_dBg}rd`ZMnc^uIvAqhWY2ZprRkfs# zsTZ`&aDzBx;#&(;GdaMI5@XQOqND)18DD%nrT9?12PkrG+antAvIkJ+L^H$kuhGKd zIVZgfF?wsN7vJPBk|xQWLNAOta|qI~@Q|@VYt;*U*&Fc8^m6oy#>&Q-vRb}~>uuZ^ zx;2OtKE{_hzSy8T1Sok9*paE0Mhqm@jE%ShoYz$82t~EwOavFgpZaGxB=94O)jU)z zibwgf1>UOOjshg6;0s7!jek!Ls5Io6C2>sWh*ys2VBkCM8uL+N%;PGNaclUyHVI~PNi`o z6ztx4Xb^Eohf!IX0VcV-j3q&KEi(x5;~`n9anV?UzwH6n=P34SdiE2POjC!8gm-qh%R-| z<(y$D66xw}%ug#tz@II0!x>WZZ-4K! z^}B<+EW233_fN!sWiyxSbu+#WexQ%6x{kRezbeV)^ExE0tW#|uP-l8O?OTpjVA~n> z6_$9gZ#y|&yN*in3y-;4E!ulrcz-fzucPy3!jO@P7NnPz)o*fNyK<9)S{d!n&90Nr zaXYY@F4!}1uD!_Yd}AKweWLgbik#~9_`Z!8yU$v_m(*`~I6aS_W8g(RTf2Jbzbs?g za(b>4^pfpuk&i9215+T&;aPZ!4S1;%u&N|6LnEh~Mzr?)+#?L7`Chyv)i+W7k+v z!K0+C7x=T+W(JfbWdnOUQky%E|HboidEwqXJ}o^>vl3cfU0i(_K84)h{dHG3QG(0i zvl3B9Ua#XRRcY_<)zWW&9F}4brDTl+g|$;UE_=axm&e_gFTJ-XZ`b!E@{zg{F8`O& z27A4I&gzYN$APfiWbq2|&q?LK^x8n60kg}%)2Gc*EIy0zNhL$?reNFC;OiB#$Bb8n z)1#p&LO%0Ex{~Y3b~b;7$j`l3EhbJ|LC2?;)~{S1cKf-fB_N%TeLy#l{htv3t#Mnt zxJ%SEAH$vO6{Z+sL9fB0%MR@1CfbImr0(GGc(B6FPEYmK`Mrl$3Yrn(+C1Kem1t}c zQ}^2Ko+-Q~J8nJ!?^RjkApd!Vd*Zxr3i9(@AV!Y#f_eENCt^|ehhG^6uM7w{;_@Y&!pnBwIUteY_~GQH;h zFj%S;?63RdiU7^_I&H4m-!WRrZ>wly(J3XhE0pIp=A6snI(fF&;M!mAJx;LK#w;_a z$@q-Kaf&QtzTx_0#(B5|-lF77i4fntxi!%nz+0{DF17m{9II(K+w_}r8Oc|{#|Bk6 z4}}_Ct*Y5>B!(bY55ie$^Ou@UC(Lb0|J_hnY9hDb$=V$Ce576j*8p`Pnjl>=jR zNgN|uT%;yCGXmDudx%)8-2%(3p0=)bzj0%RZR^-?lX?IkN-{_H9r472(hC(}5Ig_N zB=b;wahb09D{!0th)Hv;MdQ1x%%A2h;rZ4iG1Wn`_{|6*@_y@pcYP2!rWPLpj*AQ` zKCqrrsiDw6uA}3c8H=rU1ccb5&4S4}tX6xiJG#ws{1+86(HV+S`qd?o>Q-+6W4>m7 z!>XwM;txX?eF3jioi?ZQIDQ@16ECX`)`m$bTGRtR{jMuNLKg^ZE?v*B-Tw3Leg8xu zKv;m+`_t3Fv6J4rqh@=n^aLg>@6$dPa=ll! zfL|7q0{7j?vIY9p@58w0o9mzYHUX3Wrc<>zgmkD^)`aI9(X*NeDd zChy0;g}>wr5!CiV@{e}B6SjM}-{;(1Y7co87&W^iCMcG}BZNM8_kx*66cbp^hk&{p zJmpgGNd3tX&UxFt-p^~b9Pr+9dh?xmOsf?OCmeVbtBN$KJR!Izmpx=&p=TX+%2lAz z(y`JNE2pYww7LBS$`uISg?X~bPc$5~xk5~JDF?nz$)%49z0|bShVPx>^-9UQRlnaN zruO_jUkwL3Q`;7z%{e1^JXyq;D#6})-E2Gkwz?JC2v`a&%ItGF8S^;(?pzr^y)#rtib zf9CykNXtCk!~)~j+g~&F1$psJ)AoRCbFI*EOT{WxIK+(t)hZ6WEf1Dtc3MQ0GVzD? z`J_gun)R!#7L(;azg?hf5wz=NsOiW2ouA*fs7NxktFW}9Yx8*CehkZ1DUY7LguHZN z2D}!{r-!k-fWh_^K|!NAY&MD*4J8_fKEAS1ZEX^$w3epeiM_|=0o?Y?qf=>4XAHtt z5Swa}hnwyN+&*Rpa`qX!o*K;T3kBl#9PVUNOPib7eHfJ(l7*_wV36|xUMCNaX>=;A zY^=G2gxJs=V1i3FTfAnmW92KY=bKAvv_)BSB()1*-MIt@eH@`3%Wy%rQBD|!4oj5r7D)%s1^e};$UbV!`;5wG*8cj51h$o-%NX9{IB!}PC}YHGwjxYwHnF@f6y1Z!E_Ko3r)2oO z-(1%TcaS1^ppxmF1)M${#r4h7x1e#*Mj|41`LiKB@_OYm0V^X~DY~U#X^X#7ZNPG> zz5b-Jz53_!w5pym*9KqTnsik%OHE{SGCB8N@jJok#%qg)LvnBMJP_iKC9Ls8YcS?U zgVLd~;FEm21!a_TP_ugOBgkq)@5!W7GQhw`^SN9-EGx4_gO;xFdO^wIV1vj;lCY9P2HPzO8bNeu z^?F<67DVuvCb@5UEBT1W5b1o{#OF=#Hn|<=4PuW_6FZkRX^^~JEM-gXRJ&Qwn(dGl zm&b+)4hAVGLL0hjZfrn8gpWL*n32hCQZj5PSus<#seJUE6}P{K#oi-UeXW;kb%}HE z@KM&f$mV$Y^vx#z-ANn_xBKZ44^l)KEWSuk0L3zBp=il}R%KFbz9?QtG_A@-5`djD zgtOJi@Yv#!zrCxXNaeX6V`z;W%upW#vqmP$XO2)9LsLis0bkQu12fU8M4e{1*yQIdpz-j_pBU0;q1+{_hJq@lX{VqhfRomDGUS*o3p zdLYKt1jU~ZNL2mW-$1=UK&nUovw9Z~Hcm2g+?#(-2$W6$D(ZCfmh!w0#3gY~6d)Zl z_?UFF1A?A@H=A&nfF-E;hU2>Hpos1WSeaezFp^_q)kmXq&ynIu2_y|fM<=#&*P<0~ z=Y!DzmG*^9{ar287>aXv3fcj~r5yWKjMXGuw~{#;mFP7&P21!*ZAcQ54U-Zacm-)E z6mTtGAmZl5(fXAD)*SJcdNzFaP~cs#qgfChxySadB-x7{d=iew02VCwyZ`43E=_S3 zJvw0pox5+7g_eHgMhyU=M2P`t!Z zdw!DL61P@S2>T%wy%~U?(&s-euyHzPFs*!G{Aw8bf zl0i{xNEHk}fYYmf@AlxKj+(mTVSluH&A}+d5(B43HlWuPs&MwKZga#_uI#0Ej>uTO zVDs;&1L5VjEjI~Md$p|raQ7-3F0O~3gj1juDXo1kFd1=VxXfw8@pL{GI>)vH>=_E( zM4S&T!n^}#@`Rn7!EuW=ngB>Y@-%9qGrb;_(jEBRD*=VXEk3obo zhKR#|53lD;rDUv9sQtU8nQopZ5ee5TBO?u{G-E@9$6i)Syn*Q}Wa!!&OfOb| z{EY88K8CdgLp3#x?+4!i9rd3zX)g1Nlpw)r2aFTP<7GV^?7FjyR-{^QFC{Uxr4BZ1 zak=cr{TubP7MrdU5<@mHr9D~t_rv1om8;P3aPF@5Aeo40wuYR5+lRtL1|;}9$onc- zP?h4_m!3srGrWp~&x-a&kMAHxR+bK^pXGF2YkFTy`ER}WhJ(&@1xLfZib$y}MOGU@ zg3Dd^=e2C{O^F}fN4K!Bmm(5~dF_X(J$m0te%g@FXRPf7I_G9G>2wnU+nw(iIY|8I z!yzGIH91_TOXmb6DdjNVBk}oSQT(<9dhmDKDSm%4(2n=3yEL}_-;%PmW;^OsDNS$= zgMDJ5hgX1f7Q@p98XvnSv9=vQ4W3S<1~xU;pu)qn;_K|!)3HvBKF<$*20FzkVsg3a z1CEn>Ygg+Tmc;%*xgS3IFdf@xr8*ryG!kMD0Dn_W?+_6Z^LsvQ27U4p3buKlFUv_S zP;rNg8)S0>P5!uUmAyj+-JdTmf}&gKt#2_>1&Ek^S!-4RIEvYp53^}|^* z^W#ToX+1G*FlwRa*fx!?doN6+es;Z}mvaWQ~R45bM&NzLm#= z&L@)EQp|KErPoR(9;X=S2$sEOL&#M@J5Q=M zZH{tu>Po35V)bjFle7+sprNMI>BfPD;9CgS&8_R$7}JpKI8`Q7CP1^x@>RXnWCS6( z5Oc<1^CKZq!2T9VYwe)o+?~fK+#|xqnZj)jo4bl};!8#UC>)HK>3WtFmVEwN!29{C zNhYMLvH52lOm67tm57ASNc{O0nepFpp?HI?x7ToFT%J2O@28~&3s?Hvzbxc0<4o5J z#HPKS3)S}^$?~uJYMtAoc|0z0JogcO6pk0Gw__9LAAA<_qP8O}CQwXYR)Z}TT3>mL z#CJW-G12$s2g@Y1%W^Tb-L4(Svm~@#{ezjTCanSo5x{_f{^0QKE@xo3Fww4(go-JCXCE`6@Get>nlBFbGO_&uNtVHr zDUjFQ^ts24P5Fs$Ju4}R-C=V!bOSOfhdvdH3seM3Q^9u@(mNKZ%{VwUphS4As+yUU zK3KeFDKmp0F2EAl1J1K(qis#^6}-n+6n2C^VCWQR0%b@_W|;ZW(hVldOq&`6julEz zmMLU0xJF-+6{lxB@TuGFhsKn9+|(hCR8~|3^W#OkG(q~Z$DaXm z1M?8hqSSG=TuLl|M?RO8-)YHNwGJHKFGzE})g*nGR6x}oG`z~3^>0)iiHwpJji$#r z0*|6gNN23XD)joX!?wrMqrclRdwUNKZn-G6u;QOXxAQZ*oj&TKE~PN3Iy0A=jELHT zcCuOWmx&GJo$5@yMaIHFx{So;mZvKzHIq0U^+^vzn|0R7+n2)6zOxf9XN0D+`#llp zz>bZY@4ilUJ1M+eInTh7+TPt@d> z$>oltdDZ0b8k_BJR;ZLY>f*UZA!+si=A_RshzJjluT3asHzjATH(D;oLtSLW2XpkQ ztQUJE&gzn}e^54hE#WR6$4cb|(Dl;x)PW0UiE)INy2C<}`r;3E z`m7y&s;R-n%FpaMLi%pcm&mwME=J8j!=^FFfl(o?LRD(_(umcTqiMpjU~qdsB?&V^ zTkys+{Tw}y)+{5SWpo zA;gh4O)Ri0GKh7mkFna$haz7VtU(WbjeoRkC--xhyTm2iFykG>y#MySLO_gAZTbOZ z$jp<&+1?vRS>;Uo5YZM2)1_S7x~1uk?zIegek3blQ_iOi6`2&(?f5S??3Al3fqDb= z=^Hq;gv&>Nh#PtYLSoH9K-jXC+p#Xgwzagh*s^)*64>fQ4)%`8tHxVVko>WcmY#Tz zCm=pE5-BaqaR})Ood5?~&g07=C>qU!S_%+gCW&|QXSZCgixxv2HKYbAbUMhM5a;-` z$WSl!r;EzOgjhtx2!gp(fHsUqz*q=XxH0Wz7JrPA#3o)WTDLI?Yp*Xk@u=G38KP5_##3M6JeM6+ihU`HKaXSWp__wJm{xtUiA9 zmzsf=)G>`Ze>vnUF-u&kxDsh|1NN;J)cBAUD~2yk>iBQ!3Q1+YBTy0tLsbWKY`jH2 zB}H^(W^Sq7$`wuNYY9}C!b^qb(d91TC|a>7?K`oumuPT@-OvnUQ=ZLk z&!C9ogxp4rU8(*9r73?JE7fzom!2E`5#uHmy67t<9_N&(@2&RjpY(L4ZYwWOQ&EEE zb(&o){)^3>`f&y29y1O#t2x#-baWb)!*ZEMZ`ze6*%(8wI6LCDL;a&)^J-Y~`JJ8% zwWgqZ9_)$Fk<{4ePGa@8*&;+${AuRtoc01{OKPc*Lu$*uD*l<%OKG1+DrTmhBw>b2 z_vqmRh05CY{U2q#Q`MLVT=;aBE%5o>qD2k{+j0UgruS$0<;=^y)~KgpU+TNp<$A&_ zq({>Ef*y>W2S3gCfQZ>1T(``AEZkGMi~yZso0=2)G_ugwDw-sK;N zr}-!Zc-oIwQ`tEWn=_CpirYQDmd)DoNjN5`lzzWoZ`=v9uSY&Zm)CwdVb%J!6>eHrfq+9if=p= zb*AG}!nO!3Q1@#1l`A^BsDW&^=%==dqzM(SFJ}rFwG~`oV$Iv*U>?2&692g8Ir@6J z#74Osek-2ro5D~kdYOC^x-$&oS2{Ric_<<3#mC20kBUa@c%5vVgxXMgN=hzI3>%5j zOZudbl}DZmgZKMKPpm?)5s)_!7qz7HRCU|NkEycqki+Y zbe=Q9)W~=CQYzSE(RfGg^*y=1zV|W2>+?hrFOBp1qcTriYq?vd_x(Mo^;(+2#|^08 z2K$6Lqs}O0iaQ=~!Xc#nWO-QW7Rw*fAr_WMNG370)ezt_KOb6kw`ryodXl9DOCFFD z|9tKAJeF=*N0J*1h%gv;PR9Ut_IMuTbqLDovRmX0dJmPTSR9vL@U?L`eMj1$LpMWd zM4Y*N_d+ySlY%3r)oE_qoMqJ^BkB7y81Q*eUM)+0aG1F7N2&YopJ5TM1C8%8ta5og z5}a_qcdy(p(WD<)qm1UOwYnp8%I0o}rnn~a7dvN0jkeCH5QrX`o9xOhZkAL2M!H}< z>!+g;-Cuy>1}PS?$(Jqa_4aqO6GNYCeqjo) zd30_}g!0I;Sv$lP=@auG77voauht?AcSnjW&{bPByN-@cp+{8b0X^SDOF8ztyDXkd zvG6;;QFOH+DHs2Av$_@JANw`}>C=_N0q_>zV#-9*v`ZbQOwmJ;x zXPli78;q$1=-j+>)hj@7xuqMO1#b8{;_dldqv``ZuiZB@ zre*(DO43h{j$*+Msind>0_0NHM_-XQ14>{uhxh3VHUF#w56W5D~|GY5fiT-IxAK-tILZNKNh2qE<2e188Meevx{ zZg`-c-82F32Ys32=^bWXt-BE@(M;pL1w)3#fC=B|r1ff1nNr;Z6D_1LY>YKSbu)w= z$tZFSZ^UnRn{@pc`wjL^SeDNRVu8`Ig~#K;!9Twg9{2ZsTBDan!UzQYh3Swo7hB+U zH2nXbIMqW(&BS6f)dm^Wg|(;hG^Pef76Pl0E{TfT(B8grQ=I9HuA+j=no5*C{Zf#Uh5?PV_%7 ziswvi7dog8i$K)vx@v)nswXAsJBP5+oZ`h|~R5y8@( zF{Td| zTR==Cf;gxI_BszDE)PPXIs>K3wU9^!W8)LzZ{=TDK{Mhk4NITj8fMFkg_;PQ=%;+| zSe+nYBa#9?qY9}rnEMp~)27T38It>n=sB?RDnNaSPDI6o7+>EdL(V5jWGHH_Bg`JZ zb92ta0kk}Z8#^@c`b>T_R;fdZrx~COOnCjkWxJP zhX6U+H2)7hLlk>2i1tp+GjXTK%l+?6+(VBHjyNMV%#xB+Yc6c6KiKKHi3ZgX<=Fiu z2dO0n`rYHVun4JII#y~?R0{dLUN4=1Rc(UC(RYvQ-*Jq-jL~OcP{Yg;*=PcG`&h_s z-x2j=K`<$18_F{e3OIe_IaWA_3x(5S^Mn#SA4+#|kz+_p;9AM_L-W6#KDFuON8NIE)?U%8!YR2u;F zMpFHzH(0&CqEI|^5`gu~XWP}?A63d~k2H0CfokhOp`tc$0|_gWt5^iGjXp9oPL9r!z8UG->Wln8-=JcP>dQw%_R$*3nZJW! zu_4};Sk4w_@&s5KhaQE&^~(g4;TzglXBCJAFSa_jON3USw&SF1mhI*A!^p%ZM6g?a zX)|ElBaAiTu{i&&Tug?!bu0{HN_l%-?)acaet7@81}_rq8-|2?w|lhIExi<%dXHS4 z=kc(bnIIMXb6+G}UN)=cW-6Hdw@;Ic59d{T&Q?RiN^7tM6|(h~$7;-;$N`hSwxG{+ z3UI>%A_U@kEx`7znZ@0`@tBLre%zSa};*Ed> zHiJQfS63NAhWuHT$2_)OPP^&RD5r_~8y;JlZ5LmygRb-$O@K%C1Q!tm_wGbno_3?< z@M>YC9IvaF7oFX1^AGvkrtC}uX_p1Tk@z%C9TVA)bhUfW+Qe)9p32?#XFI`^4uQwh zt|Ui=4Q-B!Mfbu$snC(b^@-}ozj6Q{pOL#ND{RK}wN>dK#tki)He=ON0*N*2ZYQqC zo z9|LzK(H!3N^o@BRHbUlC67_IttLyNNA{}@(TLS8a)X5Q|?X@rd)6w&m2H$<&|9)ku zy`E3TgQ@Z^O)8}YG)TdCQK>5ZUy3)l1Z{TM?dHy&GQmTgf8-qA(C~&Ax1FxrNH%4J z*>Eo>Q^xch|H|o1<1CUB@wfNNlzP1}^LDY=APz@7=iMv&eRX+npBEir2V;F@KJcFL zj0zK~y&iB(TCZ3Ys(cW}V9bo>Auy8zSZqHy>A%E#zFPazo4X;eI$jGKLX38R$BM}H zdDzpEK|Ztq06c%C^yUG^o9-1;u-{+b^SIraSJNsIG=AMR(}L#@)TU?zvPVgmj7o>x zm~9>SyuU(qaKj;A^NgheW-|Dnmp&)%%Vu0sPcO-NTO6H$2~J4WwU}_+sS~ks5E!fx zD`hx`l)t@nN17JQx5Pww#pTz$={T7AN@oJy<)Y{u2m}@T_k$rD#A{SZB};V2*bHsd z>rS}*T7Kp|YTGD|V$Lz_(+c!Zt6KJh=@gU7|9j?)STlBN7QX)re?xw-uHAtus;U+H zmz?bMW+R<<&|;5^RYC4c!-G~>%l_yEu6*};_gAO8M=7?_62Z>gubvF1r<1K3#L;)a z!B)!J{nEK>+l`LgftUdU)@lU0fH4J~-aLk-<(Y>Ue$|$F;I_zjij1S8`lGrZo zIex75I`>5+&q+XDhJ-BCiHryI-CE|p&w~>EB5`TvBGn~ZUHh%mHPfr zX*JJoT3Bc57#UKwOCWfJyLe5f^#aKO$NO#ZHcsx-h3>CkHxPx^xN!O3u?yoC#kqkU zG3bmO)~i{!NdC~qLeVc-jvf*&D5gti8pl-oDGOHUINEN7iJ8hrN1E&!_tEW1G5phw zCl_^ZDv!y60rjY9U!!asGAh z1hdihb)Gg={RdWJVp&Ej>(21B&0+>|&8j$3xQfN!MYz{CN7?;c8q0!!6s!^4%Xik9 z%N<*dvYs}=m7hJte|_TnxU54J>HUdRVqsuud%|OK3>(D$+Q?87(@pP717IHWxUjNK zri@k8oBJ&>l$=6Bgktv=vqv27(e0-;TxXewQV93X2-oY7Zx;dZRJqhJaO_6S-LZ(a z%xir3jL0bv%VPf+oyZu;JJ_g`2^VO5*&Ly;s=cMc1m~9ir~wigvg>QMHDk{3N>ZhO z+Q)iSKT&mhEG5qRC{$XUM7WV3WK6N*jaH&2L(^Z$+7cv3I=J8V=}AaX&23y#EaSwS0r7{N-9-EUi>Ach;|EV@5G+y-1si$DYiDQlHT-u2!;m5?Sv#I9RX^ z5}K8JkcxRo&zLVFj#r)nSF=5M>|B|m28bRwa8{g1j##>~8!wb6$o4JB$pY_z)I(>~ z0DtWy4T&0G#E+F_Wu9bR%iO7nQX9!!j*t`W$z4ui#Yq{dF^@6fSlkT)SGJfCA z2sgSO#q2ZpCwOaZwt_CnTCccCO^eqc)!6(AykB-vIkU|UcX`bo0@1scKb{eJuu|vC zbu?c0w)-!)yD><%i|e^`I{{a594movm)u$Nv~fD~3L@zY`nDi`RQE7xc+0i=8$~AR z)#p_D{`BhV6(e$a-j*iHJxN+xFRfDPAp)0Kify0Pi9&Z4iVGXzZQS|y+tb-BW9wZ; z<^0-VM)_cTybMefJrU$nx&IIBFD(FZjU`X zNE_>W?}DMQ@n6MO$Qt(e#a=EBGu4;}tc;LL(P%C=Zw(FI{62jxutrflZk9mruSI-Z zFMnxv}co_@G2^tFM|)bTm064Ba}LpMRtSvavAhAdymv^+JtMA5m{kzhr^kdv3dCg6fWkN;Pz=Z z46^3&c=d>7_rP$IrO)KKKUf>alEZU4Tmf9i133}jpU)mDEgb`6V3-Z>Uns?HOMGwz zr}eH{_^l4o>?SPY%C3;`$IxZUmV!9`iR;=4!k~ow2y-2w29_Xk1TsXeKX1-XH%=YO zV$XobgEaf0GL#tf!4PO#nwI5t2YhuPy=L(a+-qZwYM}UaVq6Aa#LW9!$_@hQ@%Zl| zQdcGzD|n7Mq0BFQ8ndX^+ehOBw%-+Z{~~Zy4G_haAVY;*y5(#7sC0cv9ed+4^`*N? zx*D%-%Rl3}w-x9KuT@OR0eJ0mo^~U;Lf#yl44uXy!e`LtV9$@7sgSfsLr0?uf|G zz1z>Sn)TtW4tJ-|;aJ?6?Qehwtg*irpa!kCR}sY;O9D5}UjIIw0>7CSpA?y$)alk) zhnFbTaCBA6mJW8+a?LJ6W3)g?2eT`n0(h5{#XtSQab%2 ztkT8lpBFckJ+!L1L9gF)F;tbK?+1m#)JtUxlVUzQ@r*6~_)Cz4{@1z)!{7yBg`)VM zKlQ0=D#xt#Vq3ru{%)EXXs$*h)fS5}Q)5o+%|YYnB!}A(tvIBo-ztMA7kdZ$k$8yW zL5HuVK0f;$^ga?23H`hzDLl;?5eUr^qc-Z~(J~@OyFZCSEfnCMciObSHxv;~8#|PB z;uh7z5~iFQJwO-^qiylI($v1u(Y|H;F{1mW0Mv46;kIKQ%30-f(9*3XKX`LYHha_#bcCL%#uIRlc45lZ;GKAGEE^QYT36-R|ncM zE#JeUJ*)A~2FhOogOXn1EO&D&0sGQ#pP|N)W#R$PUs%;)kZ)5`(l-oi4hAxjUsqW_ zOF6LhfsGOYT|z^H-=|e3Jss@U1cVibc%&7z7E_f)X~&BJ`Ef)$2Gj}Pumy@F&4I!} zvtV$L!tm4>Fbw}Y@W1=09K9+d6f&_RkjP zM? zb5(=Itx)VktwY%r(MPopg-WnZQ`48xSRPMGq!9mGQ8^h3LtCPZAx1TK3TxJ+thMqu z@9j>0rpzkVq^CwPU#F%d-AfmR{lj#5oL!Bdj$&qf4t`9dbS`Cm7%6+DP7g>e*%Ox- z=x>`{oW7T#t(Hhj2M5oAOHY{e<3LydMey`F=me!+fP-vtRPE&2OKECB_h= z#am_i4#Roy6zvP-Ll2f%Ar-#xpLl;6iUb)mmCu}bFb&FJ2I{Q6pfzkmVpNuk31D$y zlkLoR){c6G{YU4pH&O~Mq#^o(LCBpH_%pU6xXqwncuc`M#0tw+9S~A1s(X$MKzjDz zngeZI(G#@7yqZ7zxO`ov4e&MD=sE}@vK@$a3YIHS7H3dbOBacyQ*`-xpjtqX7Rsfb z06Pm1hENAT-eqp0`Eikt*sWPorgxA^aKMTdA>jAi|1t#E#m82ky7}*LG%jZf9#~41 zy#%`?Oi&La8D^Gsy1(|;5uVvJ{OYW>%kxGU9ui91kpn%#jcbd>!)NV0n%TKt?b`LI zpoa7Awe*GO7PnKB)q=xY0Hlqt4^>ptFgdTTfK|^!=_(`p8PAs^22uH>3a20(p}=K2 z!~MLzVJb}cBqXTz4L24DJT2zJrT_=~Malt+%?zCL5>*G=++*UGHo}t~J@mIo+dBlJ zJK_1;F!)n{khtQJx;CHm1VBhv5wT!DR&NI~Ku^*54 zLR@G*0XOH3n`vv-*+8Err=%a`@Np&o>4|*RtF3}SKoixc^T5hsJEpfXQp{t$#S%6n ziw3euHRs3GA3LK9fvSm@wgv5J;Id@fC#6TrTn(Fjtu11>d)4bywyPS|aEE$vmrd{v zR}r;Vaot54rdLg-|MzOI+lHRKg6)MQ_t@#!libDY%N&utYxN-q^VR?eBlh)p*lRWvTahU#XG^q?NCHK zJftMNL4x|}0#ZB(8p4)!t?OsUz@5jJkY&g(P7wD2<6Q?|Xm7c-ZL>7jUN?>hAxJ$T z$cga9Zm8kL*9eh4HaEP$c9i3~-@BE~tIG#SiDf@hnwT6FzAr0pr}j^KXN|G8g0Wp( z6fJj@97WV`)TT(=WHbHbPs;=iWV8ZgR=%JVWuRfgE?6}dAwWP@i9kU9ztIr>9~zoC z*t`ChNc$fc>Ym4Kv}1nll%WtbkAkJT-EI-i6b*5n#G5Kzl&*cY6_l7{;!0ykT3>iY zer|A`!avBp{h)BeA8R16{z1nkgw_`{HsB(V$4fKBwL>goya|4gA)cMc)+zxdO7!T2 zVJrUa{XMK3*VFqsfVg#84{ek0Ed`Uv%#R2AT1ToO;hQ^UFAf{MjNvr7f(jQ@7ur_J zB05y*mg=25J}%zwNwPknvVUd`DpA;_Ik&uARMYb}rM+|A;-uhTU%Es+{kr^WpPcF_ zPP!(X1?>f5C~^11o^2f-wT|K35fFo%%wiUFSglS+m&*X^L!p<$oTU7k2MLkFY|m{n zLTf34B8i<}R3jXfsj7nU=@;ymzRb&=>EG@1exgCYm|9|KQ+bCI*V2}$q_LtREmLkSgmpoq zyV6>w{sa{EYnSvl)C8$Y@WCGA7wuL)VCO4impax=`V-=FcxQ$}BX$!8S(_@CKDg;% z`gz{fCg|e>Ge^$y#n%u?&ZziMj$0Zt+rE%FL{ci7618?pWnjh7HrR?yY9&u--AaO( zah*?*>PVR;OU@cG<%1Be(X#2iMy#$btvXePjSXlmu^dlGIr5kNqNhGzh@(u*FA0*x zb&Lrz;s}-OwADLMd^8l!?_;gA!bEBjjSs?@Gq69U$CsW;kg-URS2%Dpa|7Df-;|HY zbMriUlo2TW+CK0ln_heRR7lHWQ(H?3B~4eg!rq*-o5MHl2-G?3lYfFaLh>?v+eP*F zNj`jWULEbB+svNRp@$c*)IYGm7?VtnY$riv@mh`f3Nar4b{0-YjElju5p#e-krEqq z?MKeI#}kVQr9waBHwHWkoU=9)?~=bI=!U5k&i&I%L5AcqvqXKW=G;P|Hi~WQv9&5# zLHECefwEKAur6T+E&a871xQ1rLSp!skC(X)JT!%^6wA}lk7Sxttsy7;h!GzeKP$kU zCXQH4lQami*gwz*6X!Vw1Y+u8Xwkb7vWb+OV;VM zf{kQ#Qi>x}_5GE^RO2jxdJYT*D*nk0b$*=)L`R~Gg+xMSsj7mM`AOXN^VkVHm^5jN zip>NgP%8)AotkvtR3#PB>^WHAh(!pQJ1-}@bEHqnFl;eB2Zn8^HT1KP<`jfjgqJcj?w4WyNI84L+%|f-1ygvCX&JtotDNSq7RdW_V zOdk(_#_sitIigS0K>rKMFcn;CV4+B#2t#T_D!TL}J=(`<^VVrxbTsB6ci7Ibd; zt}66trQy*l7g}=Yk6)cJZ7;4#@(Y-i%WB_&iGM7^c7(yexvZKThL9cQ{Nsa!m0K>u z8>3}l#5hd|q1@M$q6}rv!gv4lRrU%E5@F~)nUL>~@>$e;v@JIQ8P;z3&0zJiz>K0D z&)1{TUYSm<0`T0r=(PG(*bmryR%8Mm@qvBxB3Jf|ZGClK+L~^$UHTqh*SeQ%!8guX ztRbWGN$BSU&c1!y-At*dabV|qzeN0$m&^6!3UaXoAI49qHv@n6PvDb3eu%DfCdenC z9EVGie+@c#Dd*mmrG|DtKolvR(dY_#m zo0<7GZM8Okbn2g0#)ETypREge@BqhWp|Q)|3pNuP=6A&K!r;^TdC(AGZP{b&SVynj(}5EX`bSX5*C$?8W77{WOg?d2kf3_Lg=0rFh31uAt|R z&4fpq6i7p4%smY`pv24?#nn1JDfMMd*>eaM8M34Kx`KbMT1$!6#)dXHxSC*%6yz4Z zpvTe(eS@wb3KKd5DlZC|hB)RDm}Dj1sxkvQNwi9c=!L9lp4$K->eJ`%K^;wG8zSfo z9yhE`(0QQcK1^he4n(jWv!Q9yI={@2ke}xNq1tV5eyFN9lS3`N_ zRbu{7BCj&;-g#j;WPp;mgh6(|5et@3ShlTyGSFYTweX{K`1|Ygz2NKx8b*YY1avqp z48_iB!oI%v1^H(Z_{ZAI?PY=S^{?suY2GhS)}?zNDNjNe7lzmSbC|Z4kc}18D@$09 zJhanTnzw~u2juNn6S6#4$}UC8Mz(LZ3Z#iK=^1sJ!-B}Y{Fma%AoiGsi_sz>vG>`= ziWAa%Vifp(!0c}`u1%$f_k1W!s`qlb!}m4M(sT#Ry*A$+m!6g6t7eREhJ)w4+uV|_ z`KHt#1ne9i9C1O882EM9K|?3<&Ac$W{g}$4pu&?5UgWb%SI7axs+$id(-#T4RBW=t zwfez@FulXge9OH5P}`y6)y0XlciV4i%&S4O(!!bNNm?r04s&S(*^c*CVQG2cak3s4 z7vX8=`^E6$)LyYa0Gtu3Hz{+i)v1J$|C11z@R`V?H_A6`XjkUxq&Cm>84}|cGRn{K zOE1h|o&YHg3jw`pEcbhONNmH71%I2x1qyWuxE|>whd)Z6NvUtK|EG~F4~KetP-+a!-@uXc$^Kb-T}`XRBFk`>a&Mk&+px$)7H9dYEKB>**@hWkO%&M+zMnjFKNxU^fR1yACjoP1d84zd%IXX{m#p!&Mgr<#Tz(K@kCT3^LB876#nJv7 zf2hRTN{>g$`KNcGVt9umQ}Tp@+Kb!rt^X?cbkhdHt|kfodFVoSrS{PXeQ85iA#< z??FCkfo(o*7L#021&Q)S*#Ep}515*{_sMYt4i!roS$7A& zOiXvcR(JbeW_zf9gsFNeBS|zx`~;)$bx6<#GbFB~Q$N9VAn7pVLg2)gvC8=7rB=Lk z868{vyw}mc7etfeq(@FkE}*~6)w}v|_9JR4$4xIDdVIoT?Bm2NfM3eH*Z{gkE$~W*0#Z?-KTU&L>>}G;aQ0)Dn2Nsl~4@suAu_ zU=q`1wYdNi(O0<@SI>1}1piH@0)p@7HWLy_qZjXAa5)jVcR#|U@q-LlH^n&M=={qL zbdzRF`cz3WpCf%g^BpY8FW(%e+q0)|ATp@(#>yjZcSJ6BXa(72ULr+1H`_22w)8s3^KNWa104oj*ni-z5mb!}XT9rC^Vu~xxUHvostGkZrp#fv*+{ z8Xj7iaF&%a6dlk8-*oh3PtS9x?2&XpU=yHY{cGJpp<|B(?f!O(!B0r5+jbb=>O&^k zrp7bPnqFV?O1)|zQdS=-#iigA251A2{^fT<@UO6J54$qMV0y`CjD}*Iz@<-;sa9|1 z31Ui`YhK|KS}l$N4IU}8p3G%989D}BDZBdY*!ulKq0q^wS8k!a(Zn&q%xi9W#verj zD?b-@ZluK#eH-}8b1XUoCzmojJA$X>-z`TPW}>bzmv&WRLztb6)i}$Uobg)BUZ+~| z@i5;O4LYR^`LzSj9tVUp)(^8m{p6WM>_N3x7l{c(=fm2p^0P#{e!>L1Cwr6r{II?O ze@F9RIP%5WrP!v0*wnA6C6mIE>G!8iG{Sjemk!?4aK}Xv9cy2Mqk@%bJP*I*(bW{x zOr6XT85CCy(NY-mD3QmeKBsFR(Q>N6R6PA4v0*SKanCNJx5UYOy?F2Ev?(iFe~=7J z@6S86%f399YPhS?9Twjw){n$lyMmh5*d-EeM2>7Ymgr#M0*OVKy?aLlRjy=Q7ku4b z;{DAwH>7mf=iYM{>4dPjXWb561D1iP}m&-6;HJ~bPvC303 z;osRy>??@G(84kkYi`xj*M&R~Y`lw`kTDEWbGe74(1ztxu@hh*+NXu!hGF^tHfYXEs?2iZLc4^Ai}YzDEa}QC<_dr0tr(~|^)9PCiyH8YDdh(|D6n5F>?>yDl`#kxYfCuaS_ogTgAl{S5AdbXi?y5rep z7rAL=g>+w-Pc4E4gB7h|%29|e4$!Qy#b z_O#}Dl$p!j@SbwNc~&NU+G$lyDou@+tm+1n$IsjY(9jTgey8f>1gfizo3n#G5(V_K zb7)Oyb;C%phR&*l*|&A8g8%?8(dJ5*%v#y-%K*@PD*IqfY=W^qu3$3r?O4&pGefcE zY11}*P1wiz1S1*SQzx3Woc{bIuJjaGncJt-+g%|pka~2^1(Ta8R&~uyOwlSSOj4c+ z(O#A<>XW*l0(~Y#=v463VtP>?yPttSM#FjOeE_dw+bDyBi9YJ{{oB4Pf@iSsfOty;k7xCEk?!ic=ybqSc z)g?3Ln4y3>PJT1CerRID+|cnv>vZWE=;Tvn-yaj-f$cwdMvKe6FCf(0avaxgPn6FK zz%`4>?kit$dIKOGikM%A;%0R-lE;1-FR69j-Oa(-5$*M}t{GAqgmQOBc-XkvBS70L znEe8g8hli69$xN_UiL`jA2we9BB^D(Pf|hJ*xK47>`4P~_X63Xy}bU-|Im?AMf=Dx z7!A4h8QFFp5V@q<&WSi6+-*?yn}eY?eE}*cXIC3Xdn8E18Rcr@f&7gRsC7y99cBL1 zx}=68RgOdd9z|`PkSH4zdW*NI^+pZn;qHO!P7A{e9Ub+|idV@#sL6X}DZs6Q_$pp)zd=qh+TK#a_cbvAzg14CFdMiyS!kQmI|J ziD{p)p&wUCOcU{|K+KWg*7|c%xA^(hFi4&8z}5PL1#oDY;-C<-o5a_>=d|q~0$4g@ zOnc%NW|db3-U(O%IMaojMsd~P`s-UYE#8T8bf*x20@% z0=I_dKX>vkf7+`haN+&>ygdFCSBG+m2$W7TJYbM2DRG4;A(BDmyEJPH0K!uc| zpSw?zte_Mdpu+MWJ>8vb`;d6`{_8P{zW%=~Fe)q*z1^LKteg}Jr^2#TfB#>e8Y(l|j7#z@|K_m6u&j^94#tX+Pq?6vFJgO@LvRBhPZ_C8U% z`VbEJTcS&}<>FcJ?kS~>38YITNJ^g`@D5SU*ME=&ba_yb+FE2}c)89A!Y0~0Lhi$J z7Z)i)9zYmP(n$+KLMUNcj3}NTo*@=cBL2Vk3ZP|(VWA8q;CMdp#v+9fYeL%4l9|$X zGy1-h&Ub{q`w&wi$(Ce)_T}=up)`SV?^u3xzVGR~HGOXZcNW=Cm$^;HxRJKx9ORc| z=cB6wYb};P5s_pPLj=T)IFLIK%_GuO14vCLVj?6NgipdCmk9m|$)tZ{Ud6fp9Kg<(C{i2a3o1!8E;uxLj?;2fu%CQA_Cww zg|>kciv_u*Seos{{ResPfQ(JW#X2*QNvv50%xnG+^7j4*dHXauFN^p#(Pn4|&nD-^ z-n*&3%Obk}09UWcxNOqkd0(pw7PPgd`3}~bZj)p{|K@^kq8+e>sCqva`WJPnmRt{_ z1=6#u$u_<#ggj-gJ}E4ij5+X&^qJE7!3fvM2B=x58wj4 zHF0OsExG-{l-8OdzAlLrYyxp4UW65`ps}NZJupq#ChBsiVp!9tOnJQf5xiS+ok(ZW ziI8Y#N4|}djg4!xbFa~I?-+0GYz?u|&VJF(mfRUoH+?h<$>_tdQmj5jQRVYt?uKf{ ze2l=p&}JDVyi0}lBwa{XIiX!#735~fdeMD-rNUQ1AB0z(gik-2TM5589xd_zZwD6C zV#CGYvmk=D|F88a+%>fQRpWOy62G;P_{MOyHoc~tW=I3`kg3QSCnTOGF|+~qWm zsa*UD{T2Gs__oscckn`Aj2~)2w@3ToF2#75wKMU6&)_h2ZY7Ps4wEplOi$Wga2=-( z$3hyf#Me+7FY|xK54E62Q-{+=nqLXWNE$E0`GvNFmNdT5#Kc110_?E5K3-QXKCC~O zco`1kpSsd`CBC3Ilm9x2AS6d-2YtnOs6NKd1`Y9i$gdi&gm2c6e;m9*^-1f?Nv-@^ zFlMT=TT3a9627@Kz91oi@t^&)eIOde9f$2XSi4_Po45p)dtV&u_*cRIgA zeSWr5JgoQVt3Dn{I=?i&9$yykK+>grr}50mG+91G=}Tr0zxhKJ&zWQ?#QQ=Tn;62l z22(Bqn+6hktb-xD1I3}Mp%o7q&qHE5=6ZU+US&@yVxtxl-_KXWS!<)kFk zMD;>R%2xdwEv4)OxX0Dt1BJtsd_Y=#k{5+Cp;R5oOA&-FuNDYf-$P2uWVq7Szh}=L ziBubDS3}3ucMH;fO%@0Cm-cJ2IOrBsduLdo$o0+$r{n}fl!SGL0$f?|j8kHT0w^(h zN4@E3VHw9@;-Gh?g;jM77{BUU7na9M0T|7r46F)*BOud6F|Uer3<#AVFP$m~&WpYZ zQWl~aq(3LrqJw+T+DpvD^k!RhE%)u9qJgW%lqs~}||nn5}=1;pJ$ zGl;DM2oUORf|K6HZGuzruc|{OXa>Rg|5riELNtR|HU-4pLoTQB^)y8dtQ}M5=LnUYi!S&r&LCQij zgYcUI;_jgtq>};&5bAA$3#-O$g3Fe#szW7c25Hw6kg^cXARU_m;_jgcqCBd*0|+y! z!ki-aV;e+ zh&$}t@`)V;X9)fzg-nHw;57K0OYCsLgq%!NIJv8G zvew86)vo8HMJ4?8;D&lmrYf8~R5{seXyhdCdu1W-&u&xCskI6xHNMwLBPV&^ z1Dzh^spr&2g_9cJ>!Oj9yziBT6x{iso>N;DPHKFwt42=pzE>7fz4oqpPVH1UsqsAz zjhy6tuPmha@sH{`wMR}~U-3OYaPn%B@40&f?Y*y_QwJ4JYJAUDBPV&^bN6`j^Gx-e zELAwE@jVBPoaBAa-J|cd5$ZWvsc=%`drlfT$@`wWN6dwPsprI3;iSg*Ts3l%_dR!y z-&4!gbLyzVNsaG$YUCvEd+r{26&dO{8NjY5%mQVDt-sP>+d-n!=IV>OpNAK*5!iLG6@4<(-F+HYv91LG2nq!E2O3 zJ1c?8`w1aNYwO2+W%cbFK*2$jL7kOA#m$Xv@DENXhsGAa~eC-nww#7v~ zr~?g}nUNS1OD*9|QLKG-OBys2&ZQ*67FjGzv2gnphf*!r55)~loLu2MZe-H6uMLhX zjbK4$d5Wh%=_*i5*+%fO1}2XIl!%H;O3O@3T*Av%lE*@#M*=_!Je3nil3>D@2_dmj zsc?f>K`PvyX^@Jcq*5`IR4RsA%H|Ts99_v0UOy#KbR}lAC>bCEiXx`P;*)-Gcqg5H z7r=p@G?xGV``cFEBOOeaN5Ep3TD34*dyp=2r;TmW<1QPAU$0SrQx zvJK#?JhZFe065e1%Z8&Wt zJdj2N)kA^nq|wKla0^RiK8`M<1A9T(n=q9lrL;k5BjSQ?A?3q&U&?L?#{yuVDp-^v zs1{La@o=6likd85!t1Lj0=t{Um=+-gOj%8PO&XjQLI2^CD0ohWYQx<-saden>-#Vs z*d3NLeKP^JhaxPit%L&~YclD=%xoDw9`}l+K)9h?4+Q6BayU@gd_@o~4rCq(=iO52 zs%9#fOWbpKkk?T$FPkUfk`QHg0;7C0`8#kY1LA>h5k_T-MKJ=Eu7TAa+#(FLMS(@M zTS+JRC^l}kOU1?=`FgSSV4e%xNMS;8^3)}~cqM`Kphy@9F9xBeg6vwdPC){juhKpM zH%=Q`8$(H38$(H38$)5s=$4}e2C!A+r=zBi*p*%Dj`(a>t!s(}$Rt~bJnnfbD5M!l37d8#xGj+q8VIMy>=gM#U>`{|9{&rnK~lJ+@0 zK}_*SQUU=CpF$aMd&mE;Nf_(6gZ9-MlR`-qXYSs2N)f2K*juu1B@A*!-AE_uozLAe7CC9 zsMz{2?;J*Ze;R0@xl6?!roK_NBz|Z&+F1P0&`{DvpA)FGCAEQeDM z5!g=z?+G+d`H2XA$fg|vtSOs@N;@H(nP@9aM6{vHXqc90!#8btDvvjuQYgHt6ZSUd=X zbbHPQ6NR#IPU#8(cD-XJ#v}_|;D|=J2uI4a%v3Nv47Xu1sT4khVhR#NW70AcV&cS^ zB1!~>!bQo6$!U;0BrRDC{aS=5Iga8xq*3C|&_xaPkAeXwh)Ne`B#X_U|IJKK7bF9? zkYJCuGK?i6H@` z3`iCTVD`gDP_RT`jF?Ikil)G4k;oWvvM_@$7VX7Mn`^27 zFg#q`-GG~`izn1ukSIAVB?Ho!IkVl}_=gm4#ad?0g&0#r8$JzGF7u>mFXQ zedxRyZCm$_*=)4(-JxSg9Jo z$}fI!~Ny(LSo*A#vHrqm+9 z<@~`;buOE_%-c{t;$+mvHoKmVrMg||R`dt|t^PvOQ@af2MPEwfw{d=ayw}=!HI+9< z2#(y%+mkoVYiwEA35of*I^U;e*UGX-WrIZ|F#lAv*XEmBo|J%{yukiY*(6#7PSn)} z@3R(N8h^^wU{3Aqqcg8$4Z3=&wcW(7oAU#^ZpW5LJ!1yA@EtG8;OdJyP)A?f}^pX1rNrL#9}vEz-Joc`U$Z!3$Vk3?MA*t^`V z-R6G#T$h;|&8-MO61gKF{z|Fw)d9hkp0T#sTNY1M!YuVcH6WKeR9tCsLx)+2bSI2HB>iTf-(flH6>vhY^#Rop#`~s?|Dw;B7xy4LS za6Sb5KrBw8QmL+Tcj(7rpkorWpzpA!*WP!25d5Nxy&l_Jz3`K+ z9^iL_wpqs~1Y3ig*o+EpD0a<=fx>p(jgPf@nmxSc=x*D}sjU}tE-ZOyJN-mtWOcv( z1bbg$>Ym=o#t@%mP$>(OL(p{E)Ue!z+YRKt0=xW~ry91VC zyLh#!(?6At`L&}>`-i03Z1;@kF}Bp9-FvL3?ppX;hvg5r$J)7C+UPEtcHruhrv~rN zh&M+$6by?ETH@L-!eG3S4(IBr`;Vhi7v#PQ(ks5a@yPaq2f>2us3@MBNo9e~mbo_r zf8TKFV$TnwzhealoNQIMYrW*;vhu@Sl5EU=6wTXaw|}F={b0y?U&m)YA9t-0j!as% zHRbf^tyZr`&5qo-?>Q0|^gk5e9J=|s=yhB3K}!}| zTzNF0c;v;)J>pBA?r1f(%L@Hv3EJy6@Y}w98ac{fxb=$DBNv9XzQ@X8N80u`J=cG} zPLa-=!^;NP=h~Ze4qocoZ_r7uQ>y`|t!Mo)azlY6Wx+XaDuD6~b)E!>s4`x0Z*zd0e?d7=3iwzwQpp{`=j@jadse?l7#)Z@r+3 ztkXK{^c`pX-~*p0tcVW((X8Wxe(QPSZ=?3dR}&-qxu4PvYgWJ3o#XV7^M}mxnt0e18(##1vS(ZN^b<&@7ru6dh9#)kH;%0?qeJkAf+l2I#!horEeU??4 zOiZ#IRM5}!H{InkKIMJy`e)&*&K>i{yzjrrR+b)?=57``yyrwCb|Uyc1o` zto+l9a|L#_1hFYQsCKK8=1MaH&XJ1gHmvz@qj^peHlPb_20zVWI^>J>2I`Kf*V zO)GxaiRE^jpKD{E^*ZbEAI5bC)BQ>#C;4{#eZu=k^Qzozz1LiI^1I$W?$w(|S!IPE zQp2B;nCRsd4|Xpdv)}v8H+|!Jivzwjikp8i!s=nw8;;RT?SUQETh@g&*9@b*eHeA8&V=bKz-^CmmmY zFQ{V8IAiqSbV@-WtLL_=v0LjL0>WNKUOH*D)9lrUTE|HSuO7_{e5m){H2!rl#ot}& zURxZhGbnN9h!U}}?w`}1Sp>Cze<>(x%#GN%op(x({_4@)FRuDsFSq_KDbrgRKdGs? z_bjXTn-4LEERV-_5{}t>Z^ZIp6Q3L^qz*{N39kh`tmXyw7!fjh|Mv3K6tll;N3EeI zecZQU#LbC!ygWO4w%uNWPGt6}-JIWzwJ=KI!VMSYE?KiHhHjBmW zC)l*&=%JQt^B!j1?EWy!C)#o4dB^<1?X7OcypF#a6J=+3XmqJXOJASCTE|wuj94^s z3%8&qv)}MF2W^M?*g9T2J+NOxXZzvbuWh!op`kWT8cQ|8chKzCHBQ0T-XOJ%7+G?lSpy#|=Nk zo;+{2!Fgl5-XUs02zH@8ad_SNr%PH-7O8%NlhMv1U zv_f+|4m`9wAda~lnC#QORk!$?CZRS3%glSNX?MWIp+|==1(hXJ&tEjqE)H2T!d zZswh7*H2y@cYFBwfiH$V{_}9^O`jRnS7v!l3MsElTV1kr{(!}n6JA!jya?a3C~9R; z+_W95BWG_ab+hDd${uSp@YuyGMi`$SRB7fojCwd8!?Z&$ZTmlFPQf3;NuCJ8i&-y5~8!?9CrvA9uSf@^$i+`L92%vw50Yd1&v2jGg-= zk9}bnRh=amUddm#4^rB}9HNubK+8;x=%H6`u24T!3e`L5YCh|I?j)X2cAZQ zxaUV5I`rE;nd&UIGo0;fZ0-!%4<@f0LqiehSIKJPr0e3azW+ESwq1#Fl$wr z?Z}y58A*Aj)PQtT9TGinQpQkrf(8s$PuZx%Un5=};F0Wzqj~i4)6- zB`q&~!jH~j54BLqER2xMy*KXX(bo`=LXTw8YfRX8&_)BmDidhr&|cqPMzi6~yJbT< z2lmjm>Nn6_PO=D3)Zb0D2_fT!Hm(0BL z(62}i{0trAkT8Wx#W=z;qT^6Q0ayG%|V<|MCuS!``6r3)03OAp@gI4cvc57be>$Ht8LTl?W18#t4@ z1;k<(z)(g&;jvGKG6o7)hYV!`RLgn_>!U$x>?({%$-zoL%!zHn2!BaMmt%vbMg&jB zGHF^s@qt1e*kH>B9oRA*u=N=cE69a9u)+R}4s5kLu%VWX2p&RYILPb3hB`2UA6-k+ zPzPMBV@|BA1|9J08OTyl=*Og?4jpAVQ3qQYC9eZVK?jaZ2M(=+9h5;GIJ6F^Ge@Qa z!^aSi?PbU)J5CdrG?d*&MxpH1^%QzfgX~;d_M%_4{IMLDw!eccC(7<5qfqv)K%p#L z1=+bW*}1gr`0D_aoh!3HS0=l>4{>Sxcb0KL9bjXQ)`3ggzl)4Q9UOtW1!YEp5)rUP zypQ}wj*vd^L1rH`Wft*+bV70=Cm{=9C|e-cXUBtN>p>zzcy@psP>0xnFuEwEzNki0dJsS+_yJZtph;*l}HkfLKo=vl9-G2-J+9et{f>vDa5;@@d|Y?qw|rdZn?t~ZKDgG$ z{Qx{ngolFgNDm&f!My@JQiIEJJfy>i&=G<)1pGgQY~hIqU+`E99%gZXfX74d;0LBV z!P6N69unya!4(4ju`G88nEnL(x)V)7gA%T_&WAKjy2qC8N%K`Xf8^ZR}RQ@&yhm8j=EfNGA;%FI|KmYd6M(u}7)jx^^Tz|ja z_k3s929u(wptsiS?##~a%+Aj4+k@FlzgcwU?5p>`D>Kq(BrMmw@`n;$D2g% zL!Gqi<#O34qZ*_;$O6|qUBg(w2p|gJn#TZfKrNsSP!CuDXaFn(Gy>oPvIwvka1US! zpc!y4U@71e0Qv@DnO9%#m3NSd?rK#B#KE5{w(OJ~%7Prk3e7*=3y-Nb(0qDUpBMAt zzZp*;zhZ%#*^2Ge_OFd&7uQ7Pe8XGZ@_O&TDBX`dLFl(m)6h(O)}y*$)Ypj?i)#G)V|KHuVJDV{w`W^ zfXLu6Oa3ZP@(xuR&{nG{@vcOBaK~`>Rl_E!FY%7`6RcHS4qLdB#V=Uh$h&352fT&h zRu;$YERI`O{NGUFs(ja44LU5u6TRpr+_56AaEXGu!Oo3kv#J0rUvQFR!)`8-$l_SY zId0lbD-3SvD(Au~`&D7o$rfEOD3#l<(n-k47t#lcwwkbq+;KD@x7${?({`V?JNNVZ4C z8p46>VC(#PHB9h`a&3(0DtpMus@#xM#K2Fe%-Fc}<({HckJn>(`^7`L~O&W#p98g#Ol73B=29rWr|cHv)1W$$-JV8|V+=u$^q zus3&h+9|DgO1X)lj4GBTWUrF<(8fD<=TCch4garFc5lVtBHevQzr5#=$dhOOQYIuw zM6$dt7L<8;?GZ$D-UUUmq)m?<+>j4$1m>H60(XZrOp`;DDU* z`1-x__+XpvzY9w;Axe_63rkawEWVho6lD~&gYpo#jT~~=@@@|nXh@bM|*08;k&VX&d$uo@7LwY6HlHm*Bf@K@aZ=me-rpaxMS=SfBfHu z&3s;Y;Tdh8{3>JDse!#p=>emE|C`se-Tn3xUjL(~jox#u|JsAUEC&$SAn<{}2Lc}m zd?4_Fzy|^!2z(&$fxrg>AGq^K;Q%Pf#GK^NKenj&wkx$BlBCS2GEraQ- zD%yQ&+#Wz!L#|^$rN%OeLQ8Ac#@6l4(k`tx5U~{1JrU{A^LBy#~=U6LH2foBlDx&mF6)jK_GK6R`?^Ewo)* zTfys~*SG5{cs=5%PuC*e#T#z{bUt0HV}G>14T$9FX{hioM6~1Q>MA&D)=_Uf2{8`a zL~NUw?0Be2Q$V*^nY8W`(r5*rCRU@S(Pd`R!n4pAxm3+}O-F;9*nbg&S%{>hK!b(w zE`Y9RurM$NI~Xhij4o)fC@=<07_3H?F;>aLVt8qQm>Lg@%W_!S$7+EwF5UF21I7(v zuzFdcW7Q3|Kvq^^4Uot9nrE<~v}ec1rNO8JeTq7Sv<|PqSkrY_i*}R?Y{)Zsy3)FGmE_#+(A*TGnS0PVgU&b$Tq-w=z0)hRuKI*!Z|eG46R z1YVEVLIU{-tQ#IVZPpMGflU}8vRGD^G2j`YZg3A;CaZaIhl8KJk_({#9w z{le3GW};tTdH(d@KYVb>l}Y0pc^1x zJ;`a9Ix9%sfWto@NSxnz$zuKJ>#yoMsyfYOKaLxE`&VzD+OVwY%?*mh?bw7H7fZ(BZ&*x=-Vwd~Q0*W}4P`1LRS!&4SzvVxvE5 z;!V*=Hu-$U;r#hllPQY$>@m!rG2DFn_b4KpNA#MQsBQ+|=M3wtd7CGn=jD9oPkU{l qvmiyK7ZQfG4hoXoThwREN0>j)a92yeJ=v|=zxw^%?a<(Vk^djbqO!sO diff --git a/spec/fixtures/foodsoft_file_01.xlsx b/spec/fixtures/foodsoft_file_01.xlsx index 2bd28fe5ba4e38d3739c2e79bd9904a8d4e14d16..cf094a793ecac8baa134e36f03024c47b46d5c1f 100644 GIT binary patch literal 10154 zcmeHt1$P`t(rt^GnbEeGnVHEVTg*%rV+(D`7PBm7$zo>7VrFJ$W~SFOv-{1CXWlQ^ z%{nLZ^r^bhRhe-kA|p~s76K9z01bcz003kF!;@5VT`&M35)uHw0KkH4iQ3sZnbC($i>nWai0SoUN8UUZuG z0&QI}J%vVEX%-f*Y2O}EMKZB0IV;ddmpoa{hs`T(ZEF3$_B1IYhWPchsp%4MGIsYK zy=le4i+0e|IL*K$5MsvD(+e|A27I@#>r`eFTNjoo#y7{p7VzCnUFcOuTkUB;EY$qL z-M84jrl7up#x+ndiMlzCF=c5%?WudYNiPi$JWR_zF{CWDD~0$SQQxPflWaHvGzh;HyH-o=7X&RxfQYk5;PikSnE!Mh+}vl+4c%I9ZTPxt? zJbvGY0tE z?r0(rtIyHUY`)a1&zkJ|9$!txoZF(@FwKF7++EMuy6sXdxfSEti(Vn6Pnnzz{f=c+ zviD8KwU1^s+xcLsdlx5MXHnl-zkdkHj}?%I`a4O&S|TopAOL`K5QR`cGvj8>=xXO+ zWoTz-^_$e zQ@{%S>Q8P#Dq!7*gAoXT1&gZ2VvexBdAFtEh-xQgajeX2SBKInbl!L~rcT{P!WjvwB+Jzpvd4QD|@4Q8j5RevatuI}&#Ba1lG$CZd-a*8Jn zjVqUvHPk50fg%#Pziv%Bthki%>u9mM$=*&9HuU@1_Q4!ZzJEme;XiK9 zPXR6ZUlyjT5aoqGl}>O~;&})=@JB9nY&Pvc^{;Wp0~?@ffv5cf;^8#*a84M8Kh8?2 zZqbC&6qaotD%*gcB>^&!U$#D_vL31UIo||S3_9)!M-y_5L{s(eN^eQh@|`oU$UTQh z^Ig{^AG?I(-1F#J>nts$M!`doq^W|p-zFiwscPjAdTKF%@3|N1_=t2n$xbUMD0SFz zu=Bxf^8H(N2pcA7>2Sz^^IFXpkVE-9ll%l?6D~mvY6RWI2f%`XnDmFo`AOAwQ5vI`d4yb~k&k=h{&Y=1TN;#)FS@2gb;nnsP` z1fu)s(lEJp?x^121!d=vi(NHL1hQFh*f*`1L8Jekt}f`JHJ<; z6KPPNB#94owBvSGVw2kGx|7J`0Cnr)1>NA)sp(dK@AN8YrT?xnCuQ=-QcwUu8yWzB z3wq*T#@Er@#Kg&w@%MrGH!GYH_q!DiJbia8NV*Ecgle8OW_hSuGQlQ)EKo{hgiedg zx@a+>_IS$6p%;}k{^NZI^V?nSvS;Fu>EZXPD;O$CgFKRRC{ewZGzhwO4p*Cx%SZ6; z3z3baam5*)2LX-3uVvm&u?0nR@=v{3k3y_WP zLopeoRfRDFEl6R@-phV0l*O&2<2FgBTt-k&#?JaEj<`3gwX&D?cJB?B@RaT9&<{)` z(wXLsoq6G?cY7D!Dzf4;SjCTDF+^Ij{p}!I>lrt9Mrq&_;-)Iu1R?{}FYhmK+Q~_s zNK?yR$q^O6yVL5~KZ%Lk#eCj{pv5;hCotFtR4wMld+KiOy*UzK{W_=HaXumV7*hHH z3MS~dkgt1y5ZE>t#0_8iq14CQ!DZ~7(P-o~MG-DLqNV;8-n^GVZi9(hTy_N0xundw z)VFK&-m&e@=MRgSXYV+znmp*YM=nnNF#S=F>(ya10|hIh3Ve7id|`CjNspYCLYf_S z*OD)0#HzG3o;SYCi@aA-E{{H4ELlh{`s@*V+XoC^A~;i|<7Y4G|(SX5q- z&(E;D&lq1~7?3tTa>>Uq0mYg39Ii=SzJ2hHUSp_;K^#o{k?IWl6?l9G-XFq%WS9Y;7|(a>bVKAvG){ao~uk zH+wrIb2<;*v-jNG-J}2KEypHCdhbqJA#7R83^VRkQ|i4&eD^nA+}#F0-pJSA)%f?$ zN&VQ?UkKF;s{=vlCni2+0W3W{mOF%@+(YjIY)#qfq-aDU@9X}^(aP~rZ`74uP-po; zAcOo!zTjbVxz6H&PvfcXlZP|KxtYPJwbkn)O1_aj4@uMdfOO1r+>?t5e>Z5=3FC1Sk2?MB~X3(AVX{r>Rs!5yVc^ zgSoC&@{HlYXl@8j8UA#CViTQ#?>To1RjKC^1ZQ~yg_vdWeo_^R7P%a&B68pa0O?gC z-y9Ky3>i45+u=rpOUGqkf#+5)-<1kygu`flhN1>GK$$$3FEV7KD9e}goTj_Tgp?t; z+TlGZPSOOl5CgpL6p-GxFgugVuYs!LshO(1gvxen+;4trFyCbqY-<^wbk>+JLR~+@ z5`3k3`?vqEf4e3hunLg6KLKn3A=hHmC|6qcwcPc@CwG;!#4}ZW1R}Jfxso5Cp4z~q z7IOfRm~_1u(yvPUC@VRlxo$OxT@SLfqmW%W+*W|Cd~l)YA5co{NhxrWz~LuQ5cvAX z`Z|S=TXqPciu;%(!jQ;U`v=bpS)l1@LbmF&#~6~2Zo-}Quvz*+8 z^`4i|am)EgHsM|{wg@qTL6O2YErc}j?kN9#-lb@#MijGjpd(?5nf`&V9`{*-t0K1U z1m+M<@Wj3?#)PeWU4?R*{re-sYp)IbR`-xgcG;I(hzr@(NV3_kQvnAb_5N(fi(!Wo zOR-^}f3&^|-GzDeFrd95`EO~P->t8cxrvPlGne1ZaFL^5uM)29Qfg3m}yeacaMxhghg6$ z>x1j)&s^&Va<`^L(r%Ll=K7N~rrEtTAG9>7c|{^H*GSe13Uo|lXgMewU7f0M2);98K#@E4_3S>0SZ+l zGxX2UvHNAG0-N=$_#AZ2U?z7x$Uk?3o)v~W2$TZtPSy^yb!iDT+#rH+w zhsL$~{HsLYHBVYUlo%j0Dxo4R?oFuBxnr`=Ib0uAhByuNUOKwcnxdkR;npRlX`*JvB zSFhFWB^^i4>wM$Bbqq~Mf=0!ppJ>BaBmQyy)aPkc&nM{R@wD~%Y&(6)O{1svVfR!I z__(ZC5R|L_ePcVl)#Lj51LNyO(CO=WuBfNtngyOfCUex@XYH(BzCakZyz={)g8IZR z%8se%HncsLAH)TH;AzFoj_VIy9P27z8a+_WtsbWK{2^U3?|X+(vgg2w9Y-FtxscA3 zM%60MjN|B*V?xyMZgDpeW|tsRJ|YvBC`*-1h~nMWuj?w9+vRY3 zh|!KA^~pp=+;>k;y<>gw@$=%L{V?|T`bs&)E_IhA(|HVHug;x{SqK7YWlQ`&0Xix z(f`X@f}rB*WqTuW-G=MF>&QLpt=m**`IJGO$g#&k<6se}ZsjQx@sF^QkLin(DK zMvkI>Y7_$FV|{L$1Tgq#}v|H?!4tP>R2Tw+54oSx9=Sz&26Cd zL`6oU_xruTkWUAseKn_XwO!{)@)i1*$?n2=Ar_Kfu+x}4IZ01$0@f5`@kOK zZCKxuZXHEew%L}5{B#C{8qTw7@eZyx2(-zc&*Lo4j3Mnh-JRlZmwjl~Y!40<)|Erj zIJ!;QG1)YaQP!*ok#;t;z0j^lEyX~7e-1}RVLfk$SM;}A;3rLFH9Uk-l8;_{M= zs>LcO=ZZn`DySx`k%c*{=R*4CxH-Zq+b_d2Ss}HJ3n@Pib(e>ViQ@Tdq&s_*Kh;=? zbG_i;YVIB}aSpabnw6@qSaf1(!Yy2TA98wJ3(w)IKDijF7R(-a=PvI})3iurV~67V z2_6NdL-1pD3sXGq7$D{gTc`Tm>-V_+^!~~Tqw8wQSL$%-EIRGB>h+BJIlPQyOw4C% z&5y!QoeTcJfRRuYx-&zgAgI$cce(JICZL=f(Nn29d2?l#xRGfsLy$1MH>`Yu5Kww@ ziyx=k%JGA3G25F9S>ieqWv%&1yIm`Eq@jU+ZQ`u)mf{~BeHhfaY~c_QNrwIuBXUtbcun~Ibg8j`45qkIWfKLKmO zhV7a=YaO}V8nJKz=fsl^oq9@MGO!Dvl=q%Td*Y44@;5eTETBQ27uPp< zYNr5}d3d7DeX>ZgVa_WNuGra5TXZ<(aqp)exa)6KBZJR@B#3ft>{9%?=rySI&`~rp zoMLQs??=#B`g27JmwLG5chl}$Ll$qaY&o|z;*k1`Q%EMUzgG*BerwZ9qKWDN5T&Kx zvUAA_(Ozj(t}fp-sv4idteg8=;mBo`sB%}YD3!w%F9k(^ofHXR>mEpLu+r#srmcbY zeEWVxiW+J?Pq{PnT+Uo$PvH}$0ld(oag4g`neVp2+Nnfq$Kg&E|MTDx3QGnq-nN&~ zo)7(qgwVLKWihHO*G7B;haVBC=uK>a`z)d%KtMh3v2DQNIr{4U)ob%CLRF$&o zR5cczjc9t@6x*cBYW0e9?~o@E1)Nje8Zs#D&Gl7OCnSOim$WpnN32D;(#4%J1F+S> zk2q{vgMR%II*v1}l9J?A`@MJ4aZa=!1HwaaV}6(nX5_zIBKsgOi8`Ju;MmQyKG|B{ zQyldWqpAuR{~T+I9wWLDL8&_OIKP=T=pnRUcKn8KI?rE!^aJ=(Y#;vd z$Fyy{&DWvBtWV3(n6BLTV}2UhYAGH0MDS*GXDc=Uss1dQ!2l8aOxBsqS+>Cg>7Hh6 zPGW_0-+hA_4uxu@nx}Y#L{6w0`Ey^s%!FE)!RimR<;~$GL@uF%kD`t-T&cc~6B@Sn5s(zEIiTefV@BG5iSZ-eh1Oq}+fg8#} z_ZA!?{J!E&khO{%x^TvVt-!FNRfvlAK#y7xD334SUeI$^+htwO$x4@znU%L=EGo6r z(1#oD&`U*3Afa~c#ZfHNhl%Ro=a7LURUt*VcnKzkr6Y#{SA@w3d(p>&9MCzNfngn| zc6S^)tGyTyy9RG!*u60*CYuTw;zHM@b;FE`hhiW{i^mozJD~z`D3KV4xX&SmUhY;P z7T0)o6xzmr&d-?iM??0yW6d%e05)h7PfXN$#+<#^# zQN;&AFi*#S3M28sW0Nd@2IXs?qQYVda-Y@fOXl}1zBm19a?xCPSd_V2fp0r+O&6*j z<1tQvbg9vl2B zr;n&8u=DG0_E2;8EXK3Rae{yNyoq4^SP}R&vBi)d5-EOy=wj|WV#Rrse>0NR6z1&C zW-4sJnuX;N;`&v9MKR;H7p_$MzCJdth4N->)r>KdK#eTy70S^)rl&q`rew-Y!`sKZ z1>FK+7Cp9`6zJ$`pI3j$_cDr zhMt!DLVWOiptxI;;`9cqC#B`jHnS7bL5uWisI`*V@jX zlDHB7?G@U4uQ|#;rPP6HMxeL(HDmd!fM54Me+tOJ`(41FJE32pzs6*LLPd%G zfc_ex{VL(F{`pTl0N_pn0Q}8c{|f)BdHhc}Hz;NMfAD`9OC?z-(CPvJ@Sw{V6cAv( I`R&*L14gzF*#H0l literal 5621 zcmaJ_1yq#((xySWK~h>I7M6xTy>vG$oh}^<0wUe9bV(@P-3llmC>AB(0`&TQ=Nt#RN%KXlzL@FP`J{p)7!> zjX-S#q@|NXq1x&I@I3cX#d!GHuy!HBHM>Q-J|_LG$3L&a-Ll1r)Zgxi-*kx*|SxKzpY70yuS3NtPsV^?q;K5+@G_+ z5t3G(ZjGH!BVk%7(3_?fx#0hYj8c&hvp8fQSNLfl$n%QYA0{RN!ilu%ER21D|1Pzb zQO!)|5p>55cn(2b_R zk0|Xwm^=_H-+`&dMLark4%D^f%XTr4*ZG*fRuy!jy#2``(9dDI*0Fb}Bfa?wC9=Xm zuL&$VJYABvw)1&;=OX_a>lUA{UFlX!@a!Rof5V61E9Fig%MtW?NnRQI|pq$cKfofI+F2z!wUJd5##V<~ysT z4SNRe=?|U2#WE4O<+UUSN}mFtQbqdG_$e4jryZYSLGDtzZlLLGdo&3qZr+?ulsH@2 z{T|8=TYnyN^{OmzXntts=X$}{cqXv-Roit=Kz+*_V*j=`?BUf#{YUwU0bZ_lAqwd9 z5-A{rOIAkr&B(hYL=4J zp3NFJ6=yCw``8OtvD7;{{uKWJ_B;eZZ}9^Bk#DiK40Z74fa9$E*IuN6W9{Vt_%)}V z&TjS=&d&C?c>kK&gr8j*wtGb)d)lLbZW$xk9wS+Ob%yv}V`;RTKk;+pjUOkaA*S`t zXwvAH!#DEBTfDHXh;C_Yw6Z*u(9WJG80~>q-@h&1*B#26Uw|;h)zA`_w-HSSkSPGb z^@oB6oEBa2BE|)MimIhw`d$Zr(*O({D2!(z4v}b88X`A1v8lI0yKZVMzu@4S=KH+l z>czP?0c==Q5Sm^K;LTZjn*jJAe8So;TB9ks0GSW^JYA?q=)s7yWEu92X6J><2}{cX%MS$quCxUNbgT7^N1m_B zX6B5jvI-4DAd}S-Q+2v1UtOJl)abqx*rgHGBbK=|F+9;P7Xf*U&D&cLD;A1XO*{m) zmy}JyT!cBjgVYB3(2JR<->LVoN}Rf)bWd%yRlU?zrK~Plo*Dp)`V~P=*0y85+ytc9 zWkRN9r;l0&YfB3p%NP#GCL~i=9lw7BW1+~AklYmTu4=q2L%RqmY$h5s89zK zqh2B^2xCf>*77O8ed9l{c#5y+htgn;{&v;kp}D33wW4X8=;3S)8N0%(=err1kEGgRJg zf~FJ0q-4SSt@L|g<59^9;|Nht)z8lJ(P7WBq1E`S+T(g2Dl)U>M^hkYj%yyRLTjgA zGeC=1yHo<70Zf#?oj2saDt+7iP>8j)I~4HqgZsAH?fQn$aY1t5ucnLp$ZD-kt4cc( z6h(|Gh8vC$1Dg{SSPDpM23VJC*}%T7(}EBy7Gcwc4SZ-~b}91^PF zYJvQroB`$^1jZ=%qDG;Xs+4>8l8=6P@ZtDKuk)t zaWmLS9hWUUxnzNdO$yq3#$ep4qd=g%s^qHt*zBq+(Jd{DqY^=w==Wi`JmQg?!O|e8WXj6sVFo;(@RYYDVp2tt~7n2 zsyV2KU#3r7*#fL);06@myoZ<`zcKVNDzNgGyC<#09I73n+emkbiszr%xn;JOwRD6@ z77+)0U5PH9cokzsX2kd+?z&q%BJoMU(s3BNU#MyY(5w&F#9SGpVB9RmpCNwike;*wCH0MZ-Uus%T=IZJ}wIG#(s`mey?)cbo& zFv$&;gdbGYAE-VJc1jG2xkwPkEIput1v9F~TH@NTxv1m3WrpQrcwM^=Y79}~a0O3B zQo_9V_FV^Ehp3td{RXlGa|ANBH}6OPX}= zML}*6Ue5II!z1vRksx^{tPz4n!ZFO-9x%k4z*pQdh#4ovUp%@cXaYF}47UYMPr;VQ zrj|{fZ!kf!h7a>&J_M5PDd*xAjLib8BZI_b4+o|YU^eMJ2q5U-tDrOA2%G28fyP3C zq(j#Jr53%JyDA|z8FOQM?o|J8>rM7wi8&>*y*Mcyy(VZfT9VIS8P);9`k$oosJi8lJu9i_M(X>pGU%$ zLE;sU6J8;ijojMx`jMCx-pQ@r{z|4GpiE2VdKFY%rXbv_c4@-X;WfI)q_{L3YvFq>~p5g%-=0 z$N38E2g!!5GT%d&Kn&HosAro zgsBnp%g*vwY3h9TR@>I0wml%NHJeOvdXK5pp_-9nnRY*i8TuwBh;ylt2-D?~d2p0r z6#@W1>J@^zN4uib{m}HO&rMREQvRUzvVo7AKhir_$88h*=FL7g%~vFMnTXp*);Y+! zjV+ghl*%L$-Ez^Z9^0B&T-$S=OcoSV8YB`jY+7?B5xUW>)@!zb_lZfB4?OAk-Zk4k zZQ53i+6*Zu-TJ6v+S&GuC+TJN8;5&7hXGJ+0|AJ$FQX9q^^b_pGuWDZtgant{;Dia zat!1;T;d-d^46}LiYORDRc5cn&MjvevwtyCH7uh1SyTjsbCSRPL*V=`7jXA>u>MH` zzJceQrn$)5ziR2fF(rcJxMP-1S1BhImD!c@+D?ZmP}OWrCRlk)DL+0xCL)rFpy=Q zMIZqh<;+a3ltZrnF`S5X8IYQCMnsjn67V6tG$TG5LqUhwk}VQdRx(dS=9AsblP^*D z=A+OlUJ4KpQS2qK)QT9ND{VIrsTCI`?0XivVt;e=K=k%F?dX9K8^hjgd_Aff9z_Q< zNzNs%gud1T8bU2Kp=^x za&47QZs$myqY`i`apfov3R4HKfGOe8EE$kfHm1VEC1e2uczHxk*%HS~r|iio*oB3!@+R#29*@yVN@dqjS1}Qt z5|-VY&jtx|6h##QOX1gBgz*EFz zK!nw6YFxJjBEpiY!qm^~My~xPXP?TpwThq9WcU zMFd)MG0+wzw!-mgR=#1?Qrq3cjAc(!%arC_8y?f?56xMxFV76lw4WM`Vm0p06!~$? zfVXE(PJ>7NH>U@ZDwlqowb{Qxs+sf{&l=Kn{Kjw^KHTtV{1MR6hv&eg^>e99u?=)e2g%uUT8eAYMyXr?7~4$er0wYd}+do_w%i&uAV5 z@3P~{Fn-K2oXY6Vs>h(1UxRvCFLYbq(wB z)!f8-sBR>k{vL77CqVkq`NeoyaZ6=Hlj3~1_Ey*{LmLAiPE)+iC-Znkm0HwPE~mOr zGANl8ASYk`k;Cx{RI;N$^ZRff=J5^NByp;d{7iyy3_1GZQw!(jaoH0ZTHG*V_c>39 z%n7Pje*JOz&Pxp)v!>SXilc>9oh-!pILG2;Um^Nbfu~>tGxp(wq&n5CwkpFV1Sm-9VGQS0D*3{}au)LI7M{Qb(y z*FBZeU|}<@r!Toxw%NAjQ}mKU6^Zn*J$Z5frnhcux|aj6E;FJGtGJ_q&6z z4mmoQXbQw9jEuxuWjfq(w%u0;educ5TF zle@K(J6v{fv4$G|B;U!MO7FOc-|t?sDOP1~y{j)e2k^_RQ8 zrI|SxGn0EC)eqk6p3bMm+ld_+Hz6`^8*>!NumWACDYrj2dKrkVG+T&eY7aOf^tXK0 z;K(3=VPf>FBjbAq(axh^$mhoiCoTiqT>xLN!w({6a5-tZAx}X_m+#(g(CvYb z`d?G~YxeEuru+U}a4m@6QSrh-*ZaBlAR-YX{8s4hN>sNB-GAC0y-r=}KOOICH@6Db zZ@Uk_)t`FSpWb)Xh+BQJ3VmfZjZ&^ srVK9&JcYX|&Y#YAJL7ifej6L%e;q+}B~*A?2nhG!FL8LKa(;UK5ArpJdH?_b diff --git a/spec/fixtures/foodsoft_file_02.csv b/spec/fixtures/foodsoft_file_02.csv index 658f725f9..866fa0c40 100644 --- a/spec/fixtures/foodsoft_file_02.csv +++ b/spec/fixtures/foodsoft_file_02.csv @@ -1,2 +1,2 @@ -state;art. nummer;name;note;producer;origin;unit;net price;vat (%);deposit;unit quantity;(reserved);(reserved);category -;1;Tomatoes;organic;Tommy farm;Somewhere, UK;500 g;1.2;6;0;20;;;Vegetables +avail.;Order number;Name;Supplier order unit;Unit;Ratios to supplier order unit;Minimum order quantity;Billing unit;Group order granularity;Group order unit;Price (net);Price unit;VAT;Deposit;Note;Category;Origin;Manufacturer +Yes;1;Tomatoes;;500 g;20 Piece;;;1;;1.2;;6;0;organic;Vegetables;Somewhere, UK;Tommy farm diff --git a/spec/helpers/articles_helper_spec.rb b/spec/helpers/articles_helper_spec.rb new file mode 100644 index 000000000..e7a39125f --- /dev/null +++ b/spec/helpers/articles_helper_spec.rb @@ -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 diff --git a/spec/integration/article_units_spec.rb b/spec/integration/article_units_spec.rb new file mode 100644 index 000000000..cf9642de3 --- /dev/null +++ b/spec/integration/article_units_spec.rb @@ -0,0 +1,64 @@ +require_relative '../spec_helper' + +feature ArticleUnitsController do + let(:user) { create(:user, groups: [create(:workgroup, role_article_meta: true)]) } + + before do + login user + create(:article_unit, unit: 'XPP') + end + + describe ':index', :js do + before { visit article_units_path } + + it 'displays units that have already been added along with their translations' do + expect(page).to have_content(/piece/i) + end + + it 'does not display units that have already been added along with their translations' do + expect(page).to have_no_content(/kilogram/i) + end + + it 'allows searching for recommended (translated) units that have not been added yet' do + check 'only_recommended' + fill_in 'article_unit_search', with: 'kilogram' + expect(page).to have_content(/kilogram/i) + end + + it 'does not return search results for units that have neither been added nor translated unless the "only recommended" checkbox is unchecked' do + check 'only_recommended' + fill_in 'article_unit_search', with: 'kiloampere' + expect(page).to have_no_content(/kiloampere/i) + + uncheck 'only_recommended' + + expect(page).to have_content(/kiloampere/i) + end + + it 'allows adding units' do + fill_in 'article_unit_search', with: 'kilogram' + expect(page).to have_content(/kilogram/i) + + find('*[data-e2e-create-unit="KGM"]').click + + # reset search...: + fill_in 'article_unit_search', with: '' + page.has_content?('piece') + + # ... kilogram should *still* be there if it has been added successfully: + expect(page).to have_content(/kilogram/i) + end + + it 'allows deleting units' do + accept_confirm do + find('*[data-e2e-destroy-unit="XPP"]').click + end + + expect(page).to have_css('.alert-success') + + # the unit is still displayed (even if not in the search scope) in case the user wants to re-add it: + expect(page).to have_content(/piece/i) + expect(page).to have_css('a[data-e2e-create-unit="XPP"]') + end + end +end diff --git a/spec/integration/articles_spec.rb b/spec/integration/articles_spec.rb index 888b43c29..0e6b12f87 100644 --- a/spec/integration/articles_spec.rb +++ b/spec/integration/articles_spec.rb @@ -1,37 +1,129 @@ require_relative '../spec_helper' +require_relative '../support/active_record_helper' feature ArticlesController do let(:user) { create(:user, groups: [create(:workgroup, role_article_meta: true)]) } let(:supplier) { create(:supplier) } + let!(:article_unit) { create(:article_unit, unit: 'XPK') } let!(:article_category) { create(:article_category) } - before { login user } + before do + login user + create(:article_unit, unit: 'XPP') + end describe ':index', :js do - before { visit supplier_articles_path(supplier_id: supplier.id) } + let!(:existing_article) do + create(:article, + supplier: supplier, + supplier_order_unit: 'B22', + group_order_unit: 'B22', + billing_unit: 'B22', + price_unit: 'B22', + article_unit_ratio_count: 0) + end + + before do + visit supplier_articles_path(supplier_id: supplier.id) + end it 'can visit supplier articles path' do expect(page).to have_content(supplier.name) expect(page).to have_content(I18n.t('articles.index.edit_all')) end - it 'can create a new article' do - click_on I18n.t('articles.index.new') - expect(page).to have_css('form#new_article') - article = build(:article, supplier: supplier, article_category: article_category) - within('#new_article') do - fill_in 'article_name', with: article.name - fill_in 'article_unit', with: article.unit - select article.article_category.name, from: 'article_article_category_id' - fill_in 'article_price', with: article.price - fill_in 'article_unit_quantity', with: article.unit_quantity - fill_in 'article_tax', with: article.tax - fill_in 'article_deposit', with: article.deposit - # "Element cannot be scrolled into view" error, js as workaround - # find('input[type="submit"]').click - page.execute_script('$("form#new_article").submit();') + describe 'creating articles' do + it 'can create a new article' do + click_on I18n.t('articles.index.new') + expect(page).to have_css('form#new_article_version') + article_version = build(:article_version, supplier_order_unit: article_unit.unit) + within('#new_article_version') do + fill_in 'article_version_name', with: article_version.name + select article_category.name, from: 'article_version_article_category_id' + fill_in 'article_version_price', with: article_version.price + unit_label = ArticleUnitsLib.units[article_version.supplier_order_unit][:name] + select unit_label, from: 'article_version_supplier_order_unit' + fill_in 'article_version_tax', with: article_version.tax + fill_in 'article_version_deposit', with: article_version.deposit + find('input[type="submit"]:enabled').click + end + expect(page).to have_content(article_version.name) + end + + it 'provides units that have been added to article_units' do + create(:article_unit, unit: 'KGM') + create(:article_unit, unit: 'LTR') + + click_on I18n.t('articles.index.new') + expect(page).to have_css('form#new_article_version') + expect(page).to have_select('article_version_supplier_order_unit', options: ['Custom', 'kilogram (kg)', 'litre (l)', 'Package', 'Piece']) + end + end + + describe 'editing articles' do + it 'can edit an existing article' do + find("*[data-e2e-edit-article='#{existing_article.id}']").click + expect(page).to have_css("form#edit_article_version_#{existing_article.id}") + within("#edit_article_version_#{existing_article.id}") do + fill_in 'article_version_name', with: 'New name' + sleep 0.25 # <- unsure why this is required as the following line should wait for the button to be enabled: + find('input[type="submit"]:enabled').click + end + + expect(page).to have_content('New name') + end + + it 'provides units that have been added to article_units as well as those in the article being edited' do + create(:article_unit, unit: 'KGM') + create(:article_unit, unit: 'LTR') + + find("*[data-e2e-edit-article='#{existing_article.id}']").click + expect(page).to have_css("form#edit_article_version_#{existing_article.id}") + expect(page).to have_select('article_version_supplier_order_unit', options: ['Custom', 'kiloampere (kA)', 'kilogram (kg)', 'litre (l)', 'Package', 'Piece']) + end + end + end + + describe ':sync', :js do + let(:remote_supplier) { create(:supplier, external_uuid: 'TestUUID', article_count: 10) } + + before do + supplier.update( + supplier_remote_source: api_v1_shared_supplier_articles_url(remote_supplier.external_uuid, + foodcoop: FoodsoftConfig[:default_scope], + host: Capybara.current_session.server.host, + port: Capybara.current_session.server.port), + shared_sync_method: 'all_available' + ) + end + + it 'imports articles from external suppliers' do + visit supplier_articles_path(supplier_id: supplier.id) + click_on I18n.t('articles.index.ext_db.sync') + expect(page).to have_css('.sync-table tbody tr', count: 10) + + 10.times do |index| + select ArticleCategory.first.name, from: "new_articles_#{index}_article_category_id" end - expect(page).to have_content(article.name) + + click_on I18n.t('articles.sync.submit') + expect(page).to have_css('.just-updated.article', count: 10) + end + + it 'synchronizes articles updated in external supplier' do + clone_supplier_articles(remote_supplier, supplier) + + first_remote_article_version = remote_supplier.articles.first.latest_article_version + first_remote_article_version.name = 'Changed' + first_remote_article_version.save + + visit supplier_articles_path(supplier_id: supplier.id) + click_on I18n.t('articles.index.ext_db.sync') + expect(page).to have_css '.sync-table tbody tr', + count: 2 # 1 row for original + 1 row for changed version + + click_on I18n.t('articles.sync.submit') + expect(page).to have_css('.just-updated.article', count: 1) end end @@ -40,6 +132,9 @@ let(:file) { Rails.root.join("spec/fixtures/#{filename}") } before do + create(:article_category, name: 'Nuts & Seeds') + create(:article_category, name: 'Drinks') + create(:article_category, name: 'Vegetables') visit upload_supplier_articles_path(supplier_id: supplier.id) attach_file 'articles_file', file end @@ -50,12 +145,9 @@ it do find('input[type="submit"]').click - expect(find('tr:nth-child(1) #new_articles__note').value).to eq 'bio ◎' - expect(find('tr:nth-child(2) #new_articles__name').value).to eq 'Pijnboompitten' + expect(find('tr:nth-child(1) #new_articles_0_note').value).to eq 'bio ◎' + expect(find('tr:nth-child(2) #new_articles_1_name').value).to eq 'Pijnboompitten' - 4.times do |i| - all("tr:nth-child(#{i + 1}) select > option")[1].select_option - end find('input[type="submit"]').click expect(page).to have_content('Pijnboompitten') @@ -65,11 +157,12 @@ 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, price_unit: nil) } it do find('input[type="submit"]').click - expect(find("#articles_#{article.id}_name").value).to eq 'Tomatoes' + expect(find_by_id('articles_0_name').value).to eq 'Tomatoes' + expect(find_by_id('articles_0_id', visible: false).value).to eq article.latest_article_version.id.to_s find('input[type="submit"]').click article.reload expect(article.name).to eq 'Tomatoes' @@ -80,11 +173,12 @@ describe 'handles missing data' do it do find('input[type="submit"]').click # to overview - find('input[type="submit"]').click # missing category, re-show form + fill_in 'new_articles_0_name', with: '' + find('input[type="submit"]').click # missing name, re-show form expect(find('tr.alert')).to be_present expect(supplier.articles.count).to eq 0 - all('tr select > option')[1].select_option + fill_in 'new_articles_0_name', with: 'Test' find('input[type="submit"]').click # now it should succeed expect(supplier.articles.count).to eq 1 end @@ -96,21 +190,20 @@ it do check('articles_outlist_absent') find('input[type="submit"]').click - expect(find("#outlisted_articles_#{article.id}", visible: :all)).to be_present + expect(find_by_id('outlisted_articles_0', visible: :all).value).to eq article.id.to_s - all('tr select > option')[1].select_option find('input[type="submit"]').click expect(article.reload.deleted?).to be true end 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, price_unit: nil) } it do check('articles_convert_units') find('input[type="submit"]').click - expect(find("#articles_#{article.id}_name").value).to eq 'Tomatoes' + expect(find_by_id('articles_0_name').value).to eq 'Tomatoes' find('input[type="submit"]').click article.reload expect([article.unit, article.unit_quantity, article.price]).to eq ['250 g', 40, 0.6] diff --git a/spec/integration/balancing_spec.rb b/spec/integration/balancing_spec.rb index 2d08561b2..471cf35d0 100644 --- a/spec/integration/balancing_spec.rb +++ b/spec/integration/balancing_spec.rb @@ -9,11 +9,13 @@ let(:order) { create(:order, supplier: supplier, article_ids: [article.id]) } # need to ref article let(:go1) { create(:group_order, order: order) } let(:go2) { create(:group_order, order: order) } - let(:oa) { order.order_articles.find_by_article_id(article.id) } + let(:oa) { order.order_articles.find_by_article_version_id(article.latest_article_version.id) } let(:goa1) { create(:group_order_article, group_order: go1, order_article: oa) } let(:goa2) { create(:group_order_article, group_order: go2, order_article: oa) } before do + create(:article_unit, unit: 'XPP') + create(:article_unit, unit: 'XPK') goa1.update_quantities(3, 0) goa2.update_quantities(1, 0) oa.update_results! @@ -172,12 +174,12 @@ click_link I18n.t('finance.balancing.edit_results_by_articles.add_article') expect(page).to have_css('form#new_order_article') within('#new_order_article') do - find_by_id('order_article_article_id').select(new_article.name) + find_by_id('order_article_article_version_id').select(new_article.name) sleep 0.25 find('input[type="submit"]').click end expect(page).to have_no_css('form#new_order_article') expect(page).to have_content(new_article.name) - expect(order.order_articles.where(article_id: new_article.id)).not_to be_nil + expect(order.order_articles.where(article_version_id: new_article.latest_article_version.id)).not_to be_nil end end diff --git a/spec/integration/order_spec.rb b/spec/integration/order_spec.rb index 56abc59ad..9f1bb87a2 100644 --- a/spec/integration/order_spec.rb +++ b/spec/integration/order_spec.rb @@ -5,7 +5,7 @@ let(:article) { create(:article, unit_quantity: 1) } let(:order) { create(:order, supplier: article.supplier, article_ids: [article.id]) } # need to ref article let(:go1) { create(:group_order, order: order) } - let(:oa) { order.order_articles.find_by_article_id(article.id) } + let(:oa) { order.order_articles.find_by_article_version_id(article.latest_article_version.id) } let(:goa1) { create(:group_order_article, group_order: go1, order_article: oa) } before { login admin } diff --git a/spec/integration/product_distribution_example_spec.rb b/spec/integration/product_distribution_example_spec.rb index b1cf4801d..bcb761ddf 100644 --- a/spec/integration/product_distribution_example_spec.rb +++ b/spec/integration/product_distribution_example_spec.rb @@ -24,23 +24,26 @@ login user_a visit new_group_order_path(order_id: order.id) scrolldown - 2.times { find("[data-increase_quantity='#{oa.id}']").click } - 3.times { find("[data-increase_tolerance='#{oa.id}']").click } + + # expect(page).to have_css('input[type=submit]:enabled') + + find(".goa-quantity[data-e2e-order-article-id='#{oa.id}']").set '2' + find(".goa-tolerance[data-e2e-order-article-id='#{oa.id}']").set '3' find('input[type=submit]').click expect(page).to have_selector('body') # gruppe b bestellt 2(0) login user_b visit new_group_order_path(order_id: order.id) scrolldown - 2.times { find("[data-increase_quantity='#{oa.id}']").click } + find(".goa-quantity[data-e2e-order-article-id='#{oa.id}']").set '2' find('input[type=submit]').click expect(page).to have_css('body') # gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1). login user_a visit edit_group_order_path(id: order.group_order(user_a.ordergroup).id, order_id: order.id) scrolldown - 2.times { find("[data-increase_quantity='#{oa.id}']").click } - 2.times { find("[data-decrease_tolerance='#{oa.id}']").click } + find(".goa-quantity[data-e2e-order-article-id='#{oa.id}']").set '4' + find(".goa-tolerance[data-e2e-order-article-id='#{oa.id}']").set '1' find('input[type=submit]').click expect(page).to have_css('body') # die zuteilung diff --git a/spec/integration/receive_spec.rb b/spec/integration/receive_spec.rb index a889e095f..8753dd452 100644 --- a/spec/integration/receive_spec.rb +++ b/spec/integration/receive_spec.rb @@ -7,7 +7,7 @@ let(:order) { create(:order, supplier: supplier, article_ids: [article.id]) } # need to ref article let(:go1) { create(:group_order, order: order) } let(:go2) { create(:group_order, order: order) } - let(:oa) { order.order_articles.find_by_article_id(article.id) } + let(:oa) { order.order_articles.find_by_article_version_id(article.latest_article_version.id) } let(:goa1) { create(:group_order_article, group_order: go1, order_article: oa) } let(:goa2) { create(:group_order_article, group_order: go2, order_article: oa) } @@ -34,6 +34,10 @@ def check_quantities(units, q1, q2) expect(goa2.destroyed? ? 0 : goa2.result).to be_within(1e-3).of q2 end + def fill_units_field(order_article_id, with) + fill_in "order_articles_#{order_article_id}_units_received", with: with + end + before { login admin } it 'has product ordered visible' do @@ -58,7 +62,7 @@ def check_quantities(units, q1, q2) it 'does not change anything when received is ordered' do set_quantities [2, 0], [3, 2] visit receive_order_path(id: order.id) - fill_in "order_articles_#{oa.id}_units_received", with: oa.units_to_order + fill_units_field(oa.id, oa.units_to_order) find('input[type="submit"]').click expect(page).to have_css('body') check_quantities 2, 2, 4 @@ -67,7 +71,7 @@ def check_quantities(units, q1, q2) it 'redistributes properly when received is more' do set_quantities [2, 0], [3, 2] visit receive_order_path(id: order.id) - fill_in "order_articles_#{oa.id}_units_received", with: 3 + fill_units_field(oa.id, 3) find('input[type="submit"]').click expect(page).to have_css('body') check_quantities 3, 2, 5 @@ -76,7 +80,7 @@ def check_quantities(units, q1, q2) it 'redistributes properly when received is less' do set_quantities [2, 0], [3, 2] visit receive_order_path(id: order.id) - fill_in "order_articles_#{oa.id}_units_received", with: 1 + fill_units_field(oa.id, 1) find('input[type="submit"]').click expect(page).to have_css('body') check_quantities 1, 2, 1 diff --git a/spec/lib/article_units_lib_spec.rb b/spec/lib/article_units_lib_spec.rb new file mode 100644 index 000000000..66bcacc5b --- /dev/null +++ b/spec/lib/article_units_lib_spec.rb @@ -0,0 +1,136 @@ +require_relative '../spec_helper' + +describe ArticleUnitsLib do + it 'converts "kg" correctly' do + result = described_class.convert_old_unit('kg', 1) + expect(result).to eq({ + supplier_order_unit: 'KGM', + first_ratio: nil, + group_order_granularity: 1, + group_order_unit: 'KGM' + }) + end + + it 'converts "250g" correctly' do + result = described_class.convert_old_unit('250g', 1) + expect(result).to eq({ + supplier_order_unit: 'XPP', + first_ratio: { + unit: 'GRM', + quantity: 250.0 + }, + group_order_granularity: 1.0, + group_order_unit: 'XPP' + }) + end + + it 'converts "1/4 kg" correctly' do + result = described_class.convert_old_unit('1/4 kg', 1) + expect(result).to eq({ + supplier_order_unit: 'XPP', + first_ratio: { + unit: 'KGM', + quantity: 0.25 + }, + group_order_granularity: 1.0, + group_order_unit: 'XPP' + }) + end + + it 'converts "bunch" correctly' do + result = described_class.convert_old_unit('bunch', 1) + expect(result).to eq({ + supplier_order_unit: 'XBH', + first_ratio: nil, + group_order_granularity: 1.0, + group_order_unit: 'XBH' + }) + end + + it 'converts "jar" correctly' do + result = described_class.convert_old_unit('jar', 1) + expect(result).to eq({ + supplier_order_unit: 'XJR', + first_ratio: nil, + group_order_granularity: 1.0, + group_order_unit: 'XJR' + }) + end + + it 'converts "piece" correctly' do + result = described_class.convert_old_unit('piece', 1) + expect(result).to eq({ + supplier_order_unit: 'XPP', + first_ratio: nil, + group_order_granularity: 1.0, + group_order_unit: 'XPP' + }) + end + + it 'converts "4 piece" correctly' do + result = described_class.convert_old_unit('4 piece', 1) + expect(result).to eq({ + supplier_order_unit: 'XPK', + first_ratio: { + unit: 'XPP', + quantity: 4 + }, + group_order_granularity: 1.0, + group_order_unit: 'XPK' + }) + end + + it 'converts "1 bunch" correctly' do + result = described_class.convert_old_unit('1 bunch', 1) + expect(result).to eq({ + supplier_order_unit: 'XBH', + first_ratio: nil, + group_order_granularity: 1.0, + group_order_unit: 'XBH' + }) + end + + it 'converts "2 bunch" correctly' do + result = described_class.convert_old_unit('2 bunch', 1) + expect(result).to eq({ + supplier_order_unit: 'XPK', + first_ratio: { + unit: 'XBH', + quantity: 2 + }, + group_order_granularity: 1.0, + group_order_unit: 'XPK' + }) + end + + it 'converts "4x250g" correctly' do + result = described_class.convert_old_unit('250g', 4) + expect(result).to eq({ + supplier_order_unit: 'XPP', + first_ratio: { + unit: 'GRM', + quantity: 1000 + }, + group_order_granularity: 250, + group_order_unit: 'GRM' + }) + end + + it 'converts "6 x jar" correctly' do + result = described_class.convert_old_unit('jar', 6) + expect(result).to eq({ + supplier_order_unit: 'XPK', + first_ratio: { + unit: 'XJR', + quantity: 6 + }, + group_order_granularity: 1, + group_order_unit: 'XJR' + }) + end + + it 'fails to convert "12 nonesense"' do + result = described_class.convert_old_unit('12 nonesense', 1) + expect(result).to be_nil + end +end diff --git a/spec/lib/order_txt_csv_spec.rb b/spec/lib/order_txt_csv_spec.rb new file mode 100644 index 000000000..869100f9e --- /dev/null +++ b/spec/lib/order_txt_csv_spec.rb @@ -0,0 +1,49 @@ +require_relative '../spec_helper' + +describe OrderTxt do + let(:user) { create(:user, groups: [create(:ordergroup)]) } + let(:order) { create(:order, created_by: user, starts: Date.yesterday, ends: 1.hour.ago, end_action: :auto_close, article_count: 3) } + let(:supplier) { order.supplier } + let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } + let(:articles) { order.articles } + let(:order_articles) { order.order_articles } + let(:first_article_version) { articles.first.latest_article_version } + let(:second_article_version) { articles.second.latest_article_version } + let(:third_article_version) { articles.third.latest_article_version } + + it 'creates a proper csv table sorted by order_number from an order' do + first_article_version.update(name: 'Short name', supplier_order_unit: 'XPK') + second_article_version.update(name: 'Much longer complicated name', supplier_order_unit: 'KGM') + third_article_version.update(name: 'Quite short name', supplier_order_unit: 'GRM') + order_articles.where(article_version: first_article_version).update(units_to_order: 1) + order_articles.where(article_version: second_article_version).update(units_to_order: 1.421) + order_articles.where(article_version: third_article_version).update(units_to_order: 4.432643311) + + result = described_class.new(order).to_txt + expected_table = %( +Number Amount Unit Name +0 1 Package Short name +1 1.421 kg Much longer complicated name +2 4.433 g Quite short name + ) + expect(result.strip).to end_with(expected_table.strip) + end + + it 'omits the order_number column and sort alphabetically if none of the ordered articles have an order_number' do + first_article_version.update(name: 'Short name', supplier_order_unit: 'XPK', order_number: nil) + second_article_version.update(name: 'Much longer complicated name', supplier_order_unit: 'KGM', order_number: nil) + third_article_version.update(name: 'Quite short name', supplier_order_unit: 'GRM', order_number: nil) + order_articles.where(article_version: first_article_version).update(units_to_order: 1) + order_articles.where(article_version: second_article_version).update(units_to_order: 1.421) + order_articles.where(article_version: third_article_version).update(units_to_order: 4.432643311) + + result = described_class.new(order).to_txt + expected_table = %( +Amount Unit Name + 1.421 kg Much longer complicated name + 4.433 g Quite short name + 1 Package Short name + ) + expect(result.strip).to end_with(expected_table.strip) + end +end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 3a810827d..6ef915f0c 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -3,10 +3,15 @@ describe Article do let(:supplier) { create(:supplier) } let(:article) { create(:article, supplier: supplier) } + let(:user) { create(:user, groups: [create(:ordergroup)]) } it 'has a unique name' do - article2 = build(:article, supplier: supplier, name: article.name) - expect(article2).to be_invalid + article_version_copy = article.latest_article_version.dup + article2 = FactoryBot.build(:article, supplier_id: article.supplier_id, latest_article_version: article_version_copy) + article2.latest_article_version.article = article2 + expect(article2.latest_article_version).to be_invalid + expect(article2.latest_article_version.errors.first.type).to eq :taken + expect(article2.latest_article_version.errors.first.attribute).to eq :name end it 'can be deleted' do @@ -21,33 +26,65 @@ end it 'returns false when invalid unit' do - article1 = build(:article, supplier: supplier, unit: 'invalid') + article_version_copy = article.latest_article_version.dup + article_version_copy.unit = 'invalid' + article1 = build(:article, supplier: supplier, latest_article_version: article_version_copy) expect(article.convert_units(article1)).to be false end it 'returns false if unit = 0' do - article1 = build(:article, supplier: supplier, unit: '1kg', price: 2, unit_quantity: 1) - article2 = build(:article, supplier: supplier, unit: '0kg', price: 2, unit_quantity: 1) + article_version_copy1 = article.latest_article_version.dup + article1 = build(:article, supplier: supplier, latest_article_version: article_version_copy1) + article_version_copy1.unit = '1kg' + + article_version_copy2 = article.latest_article_version.dup + article2 = build(:article, supplier: supplier, latest_article_version: article_version_copy2) + article_version_copy2.unit = '0kg' + expect(article1.convert_units(article2)).to be false end it 'returns false if unit becomes zero because of , symbol in unit format' do - article1 = build(:article, supplier: supplier, unit: '0,8kg', price: 2, unit_quantity: 1) - article2 = build(:article, supplier: supplier, unit: '0,9kg', price: 2, unit_quantity: 1) + article_version_copy1 = article.latest_article_version.dup + article1 = build(:article, supplier: supplier, latest_article_version: article_version_copy1) + article_version_copy1.unit = '0,8kg' + article_version_copy1.price = 2 + + article_version_copy2 = article.latest_article_version.dup + article2 = build(:article, supplier: supplier, latest_article_version: article_version_copy2) + article_version_copy2.unit = '0,9kg' + article_version_copy2.price = 2 + expect(article1.convert_units(article2)).to be false end it 'converts from ST to KI (german foodcoops legacy)' do - article1 = build(:article, supplier: supplier, unit: 'ST') - article2 = build(:article, supplier: supplier, name: 'banana 10-12 St', price: 12.34, unit: 'KI') + article_version_copy1 = article.latest_article_version.dup + article1 = build(:article, supplier: supplier, latest_article_version: article_version_copy1) + article_version_copy1.unit = 'ST' + + article_version_copy2 = article.latest_article_version.dup + article2 = build(:article, supplier: supplier, latest_article_version: article_version_copy2) + article_version_copy2.name = 'banana 10-12 St' + article_version_copy2.price = 12.34 + article_version_copy2.unit = 'KI' + new_price, new_unit_quantity = article1.convert_units(article2) expect(new_unit_quantity).to eq 10 expect(new_price).to eq 1.23 end it 'converts from g to kg' do - article1 = build(:article, supplier: supplier, unit: 'kg') - article2 = build(:article, supplier: supplier, unit: 'g', price: 0.12, unit_quantity: 1500) + article_version_copy1 = article.latest_article_version.dup + article1 = build(:article, supplier: supplier, latest_article_version: article_version_copy1) + article_version_copy1.unit = 'kg' + + article_version_copy2 = article.latest_article_version.dup + article2 = build(:article, supplier: supplier, latest_article_version: article_version_copy2) + article_version_copy2.unit = 'g' + article_version_copy2.price = 0.12 + article_version_copy2.article_unit_ratios << ArticleUnitRatio.new(quantity: 1500, unit: 'XPP', sort: 0) + new_price, new_unit_quantity = article1.convert_units(article2) expect(new_unit_quantity).to eq 1.5 expect(new_price).to eq 120 @@ -55,8 +92,12 @@ end it 'computes changed article attributes' do - article2 = build(:article, supplier: supplier, name: 'banana') - expect(article.unequal_attributes(article2)[:name]).to eq 'banana' + article_version_copy = article.latest_article_version.dup + article_version_copy.name = 'banana' + article2 = FactoryBot.build(:article, supplier_id: article.supplier_id, latest_article_version: article_version_copy) + article2.latest_article_version.article = article2 + unequal_attributes = article.unequal_attributes(article2) + expect(unequal_attributes[:name]).to eq 'banana' end it 'computes the gross price correctly' do @@ -87,13 +128,27 @@ expect(supplier.deleted?).to be true end - it 'keeps a price history' do - expect(article.article_prices.map(&:price)).to eq([article.price]) + it "doesn't keep an article history for articles not referenced by closed orders" do + expect(article.article_versions.map(&:price)).to eq([article.price]) oldprice = article.price sleep 1 # so that the new price really has a later creation time article.price += 1 article.save! - expect(article.article_prices.reload.map(&:price)).to eq([article.price, oldprice]) + expect(article.article_versions.reload.map(&:price)).to eq([article.price]) + end + + it 'keeps an article history for articles referenced by closed orders' do + order = create(:order, created_by: user, starts: Date.yesterday, ends: 1.hour.ago, end_action: :auto_close) + order.close!(user) + article = order.order_articles.first.article_version.article + + expect(article.article_versions.map(&:price)).to eq([article.price]) + oldprice = article.price + + sleep 1 # so that the new price really has a later creation time + article.price += 1 + article.save! + expect(article.article_versions.reload.map(&:price)).to eq([article.price, oldprice]) end it 'is not in an open order by default' do @@ -104,62 +159,4 @@ order = create(:order, supplier: supplier, article_ids: [article.id]) expect(article.in_open_order).to eq(order) end - - it 'has no shared article by default' do - expect(article.shared_article).to be_nil - end - - describe 'connected to a shared database', type: :feature do - let(:shared_article) { create(:shared_article) } - let(:supplier) { create(:supplier, shared_supplier_id: shared_article.supplier_id) } - let(:article) { create(:article, supplier: supplier, order_number: shared_article.order_number) } - - it 'can be found in the shared database' do - expect(article.shared_article).not_to be_nil - end - - it 'can find updates' do - changed = article.shared_article_changed? - expect(changed).not_to be_falsey - expect(changed.length).to be > 1 - end - - it 'can be synchronised' do - # TODO: move article sync from supplier to article - article # need to reference for it to exist when syncing - updated_article = supplier.sync_all[0].select { |s| s[0].id == article.id }.first[0] - article.update(updated_article.attributes.reject { |k, _v| %w[id type].include?(k) }) - expect(article.name).to eq(shared_article.name) - # now synchronising shouldn't change anything anymore - expect(article.shared_article_changed?).to be_falsey - end - - it 'does not need to synchronise an imported article' do - article = shared_article.build_new_article(supplier) - article.article_category = create :article_category - expect(article.shared_article_changed?).to be_falsey - end - - it 'adapts to foodcoop units when synchronising' do - shared_article.unit = '1kg' - shared_article.unit_quantity = 1 - shared_article.save! - article = shared_article.build_new_article(supplier) - article.article_category = create :article_category - article.unit = '200g' - article.shared_updated_on -= 1 # to make update do something - article.save! - # TODO: get sync functionality in article - updated_article = supplier.sync_all[0].select { |s| s[0].id == article.id }.first[0] - article.update!(updated_article.attributes.reject { |k, _v| %w[id type].include?(k) }) - expect(article.unit).to eq '200g' - expect(article.unit_quantity).to eq 5 - expect(article.price).to be_within(0.005).of(shared_article.price / 5) - end - - it 'does not synchronise when it has no order number' do - article.update(order_number: nil) - expect(supplier.sync_all).to eq [[], [], []] - end - end end diff --git a/spec/models/article_version_spec.rb b/spec/models/article_version_spec.rb new file mode 100644 index 000000000..d0d3799f3 --- /dev/null +++ b/spec/models/article_version_spec.rb @@ -0,0 +1,225 @@ +require_relative '../spec_helper' + +describe ArticleVersion do + let(:admin) { create(:user, groups: [create(:workgroup, role_finance: true)]) } + let(:user) { create(:user, groups: [create(:ordergroup)]) } + let(:order) { create(:order, article_count: 10) } + let(:go) { create(:group_order, order: order, ordergroup: user.ordergroup) } + let(:goa) { create(:group_order_article, group_order: go, order_article: order.order_articles.first) } + + describe 'versioning depending on order status' do + let(:article_version) { order.order_articles.first.article_version } + let(:article) { article_version.article } + + it 'updates the properties of article versions in open orders in place' do + original_version_id = article_version.id + + new_version = create(:article_version) + new_attributes = new_version.attributes.except('updated_at', 'created_at', 'id', 'article_id') + + article.update(latest_article_version_attributes: new_attributes.merge(id: article_version.id)) + + new_attributes.each do |key, value| + expect(order.order_articles.first.article_version[key]).to eq value + end + expect(original_version_id).to eq article.latest_article_version.id + end + + it 'keeps the properties of article versions in closed orders' do + oa = order.order_articles.first + current_article_version = oa.reload.article_version + original_version_id = current_article_version.id + original_version = current_article_version.dup + + new_version = create(:article_version) + new_attributes = new_version.attributes.except('updated_at', 'created_at', 'id', 'article_id') + + order.finish!(admin) + + article.update(latest_article_version_attributes: new_attributes.merge(id: article_version.id)) + + new_version = article.latest_article_version + version_in_order = oa.reload.article_version + + expect(original_version_id).not_to eq new_version.id + expect(original_version_id).to eq version_in_order.id + new_attributes.each do |key, value| + expect(new_version[key]).to eq value + expect(version_in_order[key]).to eq(original_version[key]) + end + end + end + + describe 'validates that there\'s only one kind of supplier order unit: old plain text or new un ece' do + let(:article_version) { order.order_articles.first.article_version } + let(:article) { article_version.article } + + it 'prevents setting both fields' do + update_result = article.update(latest_article_version_attributes: { unit: 'kg', supplier_order_unit: 'KGM', id: article_version.id }) + expect(update_result).to be false + expect(article.latest_article_version.errors.first.type).to eq :invalid + expect(article.latest_article_version.errors.first.attribute).to eq :unit + end + + it 'allows setting just the new field' do + update_result = article.update(latest_article_version_attributes: { unit: '', supplier_order_unit: 'KGM', id: article_version.id }) + expect(update_result).to be true + expect(article.unit).to be_nil + end + end + + describe 'unit conversion' do + let(:article_version) { order.order_articles.first.article_version } + + it 'allows converting SI units' do + article_version.supplier_order_unit = 'KGM' + article_version.article_unit_ratios = [] + article_version.save + + result = article_version.convert_quantity(3000, 'GRM', 'KGM') + expect(result).to eq 3 + end + + it 'allows converting SI units with non-supplier-units' do + article_version.supplier_order_unit = 'XPP' + article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + article_version.save + + result = article_version.convert_quantity(2000, 'GRM', 'KGM') + expect(result).to eq 2 + end + + it 'allows converting piece units if ratios are defined accordingly' do + article_version.supplier_order_unit = 'XCR' + article_version.article_unit_ratios = [ + ArticleUnitRatio.new({ sort: 0, unit: 'XBO', quantity: 20 }), + ArticleUnitRatio.new({ sort: 1, unit: 'LTR', quantity: 10 }) + ] + article_version.save + + result = article_version.convert_quantity(10, 'XBO', 'XCR') + expect(result).to eq 0.5 + + result = article_version.convert_quantity(10, 'XBO', 'LTR') + expect(result).to eq 5 + + result = article_version.convert_quantity(10, 'LTR', 'XCR') + expect(result).to eq 1 + end + + it 'raises an error when trying to do convert to piece units for which no ratios exist' do + article_version.supplier_order_unit = 'XCR' + article_version.article_unit_ratios = [ + ArticleUnitRatio.new({ sort: 0, unit: 'XBO', quantity: 20 }), + ArticleUnitRatio.new({ sort: 1, unit: 'LTR', quantity: 10 }) + ] + article_version.save + + expect { article_version.convert_quantity(10, 'XBO', 'KGM') }.to raise_error(PriceCalculation::UnsupportedUnitConversionError) + end + + it 'raises an error when trying to do convert to or from non-existant units' do + article_version.supplier_order_unit = 'XCR' + article_version.article_unit_ratios = [ + ArticleUnitRatio.new({ sort: 0, unit: 'XBO', quantity: 20 }), + ArticleUnitRatio.new({ sort: 1, unit: 'LTR', quantity: 10 }) + ] + article_version.save + + expect { article_version.convert_quantity(10, 'LTR', 'non-existant') }.to raise_error(PriceCalculation::UnsupportedUnitConversionError) + expect { article_version.convert_quantity(10, 'non-existant', 'LTR') }.to raise_error(PriceCalculation::UnsupportedUnitConversionError) + end + end + + describe 'validate unique name for latest article versions' do + let(:first_article_version) { order.order_articles.first.article_version } + let(:first_article) { first_article_version.article } + + let(:second_article_version) { order.order_articles.second.article_version } + let(:second_article) { second_article_version.article } + + it 'prevents updating the name of the latest article version to the same as another current article name' do + update_result = second_article.update(latest_article_version_attributes: { name: first_article_version.name, id: second_article_version.id }) + expect(update_result).to be false + expect(second_article.latest_article_version.errors.first.type).to eq :taken + expect(second_article.latest_article_version.errors.first.attribute).to eq :name + end + + it 'allows updating the name of the latest article version to the same as another article version\'s name as long as that version is obsolete' do + order.finish!(admin) + + original_first_article_name = first_article_version.name + first_article.update(latest_article_version_attributes: { name: 'new name', id: first_article_version.id }) + + update_result = second_article.update(latest_article_version_attributes: { name: original_first_article_name, id: second_article_version.id }) + expect(update_result).to be true + + number_of_articles_with_same_name = described_class + .includes(:article) + .where( + name: original_first_article_name, + articles: { supplier_id: order.supplier.id } + ) + .count + expect(number_of_articles_with_same_name).to eq 2 + end + + it 'still allow updating attributes including name if name stays the same' do + update_result = second_article.update(latest_article_version_attributes: { name: second_article_version.name, price: 2, id: second_article_version.id }) + expect(update_result).to be true + expect(second_article.latest_article_version.price).to eq 2 + end + + describe 'articles in suppliers with shared_sync_method = all*' do + let(:supplier) { create(:supplier, shared_sync_method: 'all_available', supplier_remote_source: 'https://dummy.com') } + let(:first_article) { create(:article, supplier: supplier, name: 'One') } + let(:second_article) { create(:article, supplier: supplier, name: 'Two') } + let(:order) { create(:order, supplier: supplier, article_ids: [first_article.id, second_article.id]) } + + it 'allows updating the name of the latest article version to the same as another current article name if they have different supplier and group order units' do + first_article_version.supplier_order_unit = 'XPP' + first_article_version.group_order_unit = 'GRM' + first_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + first_article_version.save + second_article_version.supplier_order_unit = 'XPP' + second_article_version.group_order_unit = 'GRM' + second_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 2 })] + second_article_version.save + + update_result = second_article.update(latest_article_version_attributes: { name: first_article_version.name, id: second_article_version.id }) + expect(update_result).to be true + end + + it 'prevents updating the name of the latest article version to the same as another current article name if they have the same supplier and group order units' do + first_article_version.supplier_order_unit = 'XPP' + first_article_version.group_order_unit = 'GRM' + first_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + first_article_version.save + second_article_version.supplier_order_unit = 'XPP' + second_article_version.group_order_unit = 'GRM' + second_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + second_article_version.save + + update_result = second_article.update(latest_article_version_attributes: { name: first_article_version.name, id: second_article_version.id }) + expect(update_result).to be false + expect(second_article.latest_article_version.errors.first.type).to eq :taken_with_unit + expect(second_article.latest_article_version.errors.first.attribute).to eq :name + end + + it 'still allow updating attributes including name if name stays the same' do + first_article_version.supplier_order_unit = 'XPP' + first_article_version.group_order_unit = 'GRM' + first_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + first_article_version.save + second_article_version.supplier_order_unit = 'XPP' + second_article_version.group_order_unit = 'GRM' + second_article_version.article_unit_ratios = [ArticleUnitRatio.new({ sort: 0, unit: 'KGM', quantity: 1 })] + second_article_version.save + + update_result = second_article.update(latest_article_version_attributes: { name: second_article_version.name, price: 2, id: second_article_version.id }) + expect(update_result).to be true + expect(second_article.latest_article_version.price).to eq 2 + end + end + end +end diff --git a/spec/models/group_order_article_spec.rb b/spec/models/group_order_article_spec.rb index e0e9c76d8..36108b132 100644 --- a/spec/models/group_order_article_spec.rb +++ b/spec/models/group_order_article_spec.rb @@ -24,7 +24,7 @@ describe do let(:article) { create(:article, supplier: order.supplier, unit_quantity: 1) } - let(:oa) { order.order_articles.create(article: article) } + let(:oa) { order.order_articles.create(article_version: article.latest_article_version) } let(:goa) { create(:group_order_article, group_order: go, order_article: oa) } it 'can be ordered by piece' do @@ -65,7 +65,7 @@ describe 'distribution strategy' do let(:article) { create(:article, supplier: order.supplier, unit_quantity: 1) } - let(:oa) { order.order_articles.create(article: article) } + let(:oa) { order.order_articles.create(article_version: article.latest_article_version) } let(:goa) { create(:group_order_article, group_order: go, order_article: oa) } let!(:goaq) { create(:group_order_article_quantity, group_order_article: goa, quantity: 4, tolerance: 6) } diff --git a/spec/models/order_article_spec.rb b/spec/models/order_article_spec.rb index cef0e09cb..78f46d4e3 100644 --- a/spec/models/order_article_spec.rb +++ b/spec/models/order_article_spec.rb @@ -73,7 +73,7 @@ def goa_reload it 'has expected units_to_order' do set_quantities [3, 2], [1, 3], [1, 0] - expect(oa.units * oa.article.unit_quantity).to eq 6 + expect(oa.units * oa.article_version.unit_quantity).to eq 6 expect([goa1, goa2, goa3].map(&:result)).to eq [4, 1, 1] end @@ -213,4 +213,59 @@ def goa_reload # end end end + + describe 'minimum order quantity' do + let(:order) { create(:order, article_ids: [article.id], starts: 1.week.ago) } + let(:oa) { order.order_articles.first } + let(:go) { create(:group_order, order: order) } + let(:goa) { create(:group_order_article, group_order: go, order_article: oa) } + + shared_context 'minimum order quantity' do |quantity| + before do + goa.update_quantities(quantity[:quantity], quantity[:tolerance]) + oa.update_results! + oa.reload + end + + it 'is calculated correctly' do + expect(oa.units_to_order).to eq quantity[:expected_units_to_order] + end + end + + context 'without unit_quantity' do + let(:article) { create(:article, minimum_order_quantity: 10) } + + context 'doesn\'t order anything, if the minimum order quantity hasn\'t been reached' do + include_examples 'minimum order quantity', { quantity: 4, tolerance: 0, expected_units_to_order: 0 } + end + + context 'orders the minimum order quantity, if tolerance allows for it' do + include_examples 'minimum order quantity', { quantity: 9, tolerance: 1, expected_units_to_order: 10 } + end + + context 'orders the desired amount, if minimum order quantity has been surpassed' do + include_examples 'minimum order quantity', { quantity: 12, tolerance: 1, expected_units_to_order: 12 } + end + end + + context 'with unit_quantity' do + let(:article) { create(:article, minimum_order_quantity: 2, unit_quantity: 5) } + + context 'doesn\'t order anything if the minimum order quantity hasn\'t been reached' do + include_examples 'minimum order quantity', { quantity: 4, tolerance: 0, expected_units_to_order: 0 } + end + + context 'orders the minimum order quantity if tolerance allows for it' do + include_examples 'minimum order quantity', { quantity: 9, tolerance: 1, expected_units_to_order: 2 } + end + + context 'orders a lower amount, even if minimum order quantity has been surpassed, but unit_quantity demands it' do + include_examples 'minimum order quantity', { quantity: 12, tolerance: 1, expected_units_to_order: 2 } + end + + context 'orders the exact amount, if minimum order quantity has been surpassed and unit_quantity allows for it' do + include_examples 'minimum order quantity', { quantity: 14, tolerance: 1, expected_units_to_order: 3 } + end + end + end end diff --git a/spec/models/supplier_spec.rb b/spec/models/supplier_spec.rb index 5216b8e9b..850375239 100644 --- a/spec/models/supplier_spec.rb +++ b/spec/models/supplier_spec.rb @@ -46,83 +46,4 @@ supplier = create(:supplier, article_count: true) supplier.articles.each { |a| expect(a).to be_valid } end - - context 'connected to a shared supplier' do - let(:shared_sync_method) { nil } - let(:shared_supplier) { create(:shared_supplier) } - let(:supplier) { create(:supplier, shared_supplier: shared_supplier, shared_sync_method: shared_sync_method) } - - let!(:synced_shared_article) { create(:shared_article, shared_supplier: shared_supplier) } - let!(:updated_shared_article) { create(:shared_article, shared_supplier: shared_supplier) } - let!(:new_shared_article) { create(:shared_article, shared_supplier: shared_supplier) } - - let!(:removed_article) { create(:article, supplier: supplier, order_number: '10001-ABC') } - let!(:updated_article) do - updated_shared_article.build_new_article(supplier).tap do |article| - article.article_category = create :article_category - article.origin = 'FubarX1' - article.shared_updated_on = 1.day.ago - article.save! - end - end - let!(:synced_article) do - synced_shared_article.build_new_article(supplier).tap do |article| - article.article_category = create :article_category - article.shared_updated_on = 1.day.ago - article.save! - end - end - - context 'with sync method import' do - let(:shared_sync_method) { 'import' } - - it 'returns the expected articles' do - updated_article_pairs, outlisted_articles, new_articles = supplier.sync_all - - expect(updated_article_pairs).not_to be_empty - expect(updated_article_pairs[0][0].id).to eq updated_article.id - expect(updated_article_pairs[0][1].keys).to include :origin - - expect(outlisted_articles).to eq [removed_article] - - expect(new_articles).to be_empty - end - end - - context 'with sync method all_available' do - let(:shared_sync_method) { 'all_available' } - - it 'returns the expected articles' do - updated_article_pairs, outlisted_articles, new_articles = supplier.sync_all - - expect(updated_article_pairs).not_to be_empty - expect(updated_article_pairs[0][0].id).to eq updated_article.id - expect(updated_article_pairs[0][1].keys).to include :origin - - expect(outlisted_articles).to eq [removed_article] - - expect(new_articles).not_to be_empty - expect(new_articles[0].order_number).to eq new_shared_article.number - expect(new_articles[0].availability?).to be true - end - end - - context 'with sync method all_unavailable' do - let(:shared_sync_method) { 'all_unavailable' } - - it 'returns the expected articles' do - updated_article_pairs, outlisted_articles, new_articles = supplier.sync_all - - expect(updated_article_pairs).not_to be_empty - expect(updated_article_pairs[0][0].id).to eq updated_article.id - expect(updated_article_pairs[0][1].keys).to include :origin - - expect(outlisted_articles).to eq [removed_article] - - expect(new_articles).not_to be_empty - expect(new_articles[0].order_number).to eq new_shared_article.number - expect(new_articles[0].availability?).to be false - end - end - end end diff --git a/spec/requests/api/v1/shared_suppliers/articles_controller_spec.rb b/spec/requests/api/v1/shared_suppliers/articles_controller_spec.rb new file mode 100644 index 000000000..eff6b872f --- /dev/null +++ b/spec/requests/api/v1/shared_suppliers/articles_controller_spec.rb @@ -0,0 +1,141 @@ +require 'swagger_helper' + +def success_schema + { + type: :object, + properties: { + articles: { + type: :array, + items: { + '$ref': '#/components/schemas/ExternalArticle' + } + }, + latest_update: { + type: :string, + nullable: true, + format: 'date-time', + description: 'latest update to any of the supplier\'s articles' + }, + pagination: { + '$ref': '#/components/schemas/Pagination' + } + } + } +end + +describe 'shared supplier articles' do + include ApiHelper + let(:api_scopes) { ['shared_suppliers:articles'] } + + path '/shared_suppliers/{uuid}/articles' do + get 'retrieve articles' do + tags 'Supplier' + produces 'application/json' + parameter name: :uuid, in: :path, type: :string, required: true, description: 'the external UUID of the supplier' + parameter name: :updated_after, in: :query, type: :string, format: 'date-time', required: false, description: 'only retrieve articles after this date time' + parameter name: :origin, in: :query, type: :string, required: false, description: 'filter by article origin' + parameter name: :name, in: :query, type: :string, required: false, description: 'filter by article name fragment' + parameter name: :page, in: :query, type: :number, required: false, description: 'pagination: number of the page to retrieve' + parameter name: :per_page, in: :query, type: :number, required: false, description: 'pagination: items per page' + let(:supplier) { create(:supplier, article_count: 10, external_uuid: 'test') } + let(:uuid) { supplier.external_uuid } + + response '200', 'success' do + schema(success_schema) + run_test! do |response| + expect(JSON.parse(response.body)['articles'].length).to eq 10 + end + end + + context 'when filtered by updated_after' do + let(:supplier) { create(:supplier, article_count: 10, external_uuid: 'test') } + let(:uuid) { supplier.external_uuid } + let(:updated_after) { 1.day.ago } + + before do + supplier.articles[0..4].each do |article| + article.update_attribute(:updated_at, 10.days.ago) + end + supplier.articles[5..9].each do |article| + article.update_attribute(:updated_at, Time.now) + end + end + + response '200', 'success' do + schema(success_schema) + run_test! do |response| + expect(JSON.parse(response.body)['articles'].length).to eq 5 + end + end + end + + context 'when filtered by origin' do + let(:supplier) { create(:supplier, article_count: 10, external_uuid: 'test') } + let(:uuid) { supplier.external_uuid } + let(:origin) { 'TestOrigin' } + + before do + supplier.articles[0..4].each do |article| + article.update_attribute(:origin, 'TestOrigin') + end + end + + response '200', 'success' do + schema(success_schema) + run_test! do |response| + expect(JSON.parse(response.body)['articles'].length).to eq 5 + end + end + end + + context 'when filtered by name' do + let(:supplier) { create(:supplier, article_count: 10, external_uuid: 'test') } + let(:uuid) { supplier.external_uuid } + let(:name) { 'TestName' } + + before do + supplier.articles[0..4].each_with_index do |article, index| + article.update_attribute(:name, "TestName#{index}") + end + end + + response '200', 'success' do + schema(success_schema) + run_test! do |response| + expect(JSON.parse(response.body)['articles'].length).to eq 5 + end + end + end + + context 'when paginating' do + let(:supplier) { create(:supplier, article_count: 10, external_uuid: 'test') } + let(:uuid) { supplier.external_uuid } + let(:page) { 2 } + let(:per_page) { 5 } + + response '200', 'success' do + schema(success_schema) + run_test! do |response| + parsed_response = JSON.parse(response.body) + expect(parsed_response['articles']&.length).to eq 5 + pagination_response = parsed_response['pagination'] + expect(pagination_response&.dig('current_page')).to eq 2 + expect(pagination_response&.dig('total_pages')).to eq 2 + expect(pagination_response&.dig('previous_page')).to eq 1 + expect(pagination_response&.dig('next_page')).to be_nil + end + end + end + + context 'with invalid supplier uuid' do + let(:uuid) { 'invalid' } + + response '404', 'not found' do + schema '$ref' => '#/components/schemas/Error404' + + run_test! + end + end + end + end +end diff --git a/spec/support/active_record_helper.rb b/spec/support/active_record_helper.rb new file mode 100644 index 000000000..9fda860c9 --- /dev/null +++ b/spec/support/active_record_helper.rb @@ -0,0 +1,19 @@ +module ActiveRecordHelper + def clone_supplier_articles(from_supplier, to_supplier) + from_supplier.articles.each do |article| + article_duplicate = article.duplicate_including_latest_version_and_ratios + article_duplicate.supplier_id = to_supplier.id + + article = Article.create(supplier_id: to_supplier.id) + article.attributes = { latest_article_version_attributes: article_duplicate.latest_article_version.attributes.merge(article_unit_ratios_attributes: article_duplicate.latest_article_version.article_unit_ratios.map(&:attributes)) } + article.save + + # act as if the article always looked that way: + article.update(created_at: 1.year.ago, updated_at: 1.year.ago) + end + end +end + +RSpec.configure do |config| + config.include ActiveRecordHelper +end diff --git a/spec/support/shared_database.rb b/spec/support/shared_database.rb deleted file mode 100644 index 180877ec0..000000000 --- a/spec/support/shared_database.rb +++ /dev/null @@ -1,20 +0,0 @@ -ActiveSupport.on_load(:after_initialize) do - # We simulate the shared database by pointing to our own database. - # This allows running tests without additional database setup. - # But take care when designing tests using the shared database. - SharedSupplier.establish_connection Rails.env.to_sym - SharedArticle.establish_connection Rails.env.to_sym - # HACK: for different structure of shared database - SharedArticle.class_eval do - belongs_to :supplier, class_name: 'SharedSupplier' - alias_attribute :number, :order_number - alias_attribute :updated_on, :updated_at - def category - ArticleCategory.where(id: article_category_id).first - end - - def self.find_by_number(n) - find_by_order_number(n) - end - end -end diff --git a/spec/support/spec_test_helper.rb b/spec/support/spec_test_helper.rb index f3737c150..b10f90389 100644 --- a/spec/support/spec_test_helper.rb +++ b/spec/support/spec_test_helper.rb @@ -12,9 +12,21 @@ def current_user User.find(session[:user_id]) end - def get_with_defaults(action, params: {}, xhr: false, format: nil) + def get_with_defaults(action, **args) + get(action, **default_request_args(**args)) + end + + def post_with_defaults(action, **args) + post(action, **default_request_args(**args)) + end + + def delete_with_defaults(action, **args) + delete(action, **default_request_args(**args)) + end + + def default_request_args(params: {}, xhr: false, format: nil) params['foodcoop'] = FoodsoftConfig[:default_scope] - get action, params: params, xhr: xhr, format: format + { params: params, xhr: xhr, format: format } end end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index 45c7244ed..0232d7392 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -77,6 +77,105 @@ } } }, + ExternalArticle: { + description: 'article for external client with the data of its latest version', + type: :object, + properties: { + price: { type: :float }, + tax: { type: :float }, + deposit: { type: :float }, + created_at: { + type: :string, + format: 'date-time' + }, + name: { type: :string }, + unit: { + type: :string, + deprecated: true, + nullable: true, + description: 'old style plain text amount of each unit, e.g. "100 g" or "kg"' + }, + note: { + type: :string, + nullable: true, + description: 'generic note' + }, + availability: { + type: :boolean, + description: 'whether the article can be used in active orders' + }, + manufacturer: { + type: :string, + nullable: true, + description: 'manufacturer' + }, + origin: { + type: :string, + nullable: true, + description: 'origin, preferably (starting with a) 2-letter ISO country code' + }, + order_number: { + type: :string, + nullable: true, + description: 'number uniquely identifying the article amongst other articles of this supplier' + }, + updated_at: { + type: :string, + format: 'date-time' + }, + supplier_order_unit: { + type: :string, + nullable: true, + description: 'the UN/ECE unit the article is delivered in (if null, the deprecated plain text `unit` is used instead)' + }, + price_unit: { + type: :string, + nullable: true, + description: 'the UN/ECE unit the article\'s price is displayed in (if null, the deprecated plain text `unit` is used instead)' + }, + billing_unit: { + type: :string, + nullable: true, + description: 'the UN/ECE unit the article\'s price is billed in (if null, the deprecated plain text `unit` is used instead)' + }, + group_order_unit: { + type: :string, + nullable: true, + description: 'the UN/ECE unit the article can be ordered in by distinct order groups (if null, the deprecated plain text `unit` is used instead)' + }, + group_order_granularity: { + type: :float, + description: 'the granularity in which order groups may order this article (measured in `group_order_unit`)' + }, + minimum_order_quantity: { + type: :float, + description: 'minimum quantity that needs to be achieved for the article to be ordered at all (measured in `group_order_unit`)' + }, + article_unit_ratios: { + type: :array, + items: { + '$ref': '#/components/schemas/ExternalArticleUnitRatio' + } + } + } + }, + ExternalArticleUnitRatio: { + type: :object, + properties: { + unit: { + type: :string, + description: 'the UN/ECE unit of this ratio' + }, + quantity: { + type: :float, + description: 'the quantity of this ratio relative to `supplier_order_unit` (or `unit` if `supplier_order_unit` is null)' + }, + sort: { + type: :integer, + description: 'sort index' + } + } + }, Article: { type: :object, properties: { @@ -146,15 +245,15 @@ description: 'foodcoop price' }, quantity: { - type: :integer, + type: :float, description: 'number of units ordered by members' }, tolerance: { - type: :integer, + type: :float, description: 'number of extra units that members are willing to buy to fill a box' }, units_to_order: { - type: :integer, + type: :float, description: 'number of units to order from the supplier' }, article: { @@ -298,12 +397,12 @@ properties: { quantity: { - type: :integer, + type: :float, description: 'number of units ordered by the users ordergroup' }, tolerance: { - type: :integer, + type: :float, description: 'number of extra units the users ordergroup is willing to buy for filling a box' } } @@ -333,8 +432,7 @@ type: :integer }, result: { - type: :number, - format: :float, + type: :float, description: 'number of units the users ordergroup will receive or has received' }, total_price: @@ -405,6 +503,38 @@ minProperties: 2 # name+url or name+items } }, + Pagination: { + type: :object, + nullable: true, + properties: { + current_page: { + type: :integer, + description: 'page number of the returned collection' + }, + previous_page: { + type: :integer, + nullable: true, + description: 'previous page' + }, + next_page: { + type: :integer, + nullable: true, + description: 'next page' + }, + per_page: { + type: :integer, + description: 'number of items per page' + }, + total_pages: { + type: :integer, + description: 'total number of pages' + }, + number: { + type: :integer, + description: 'total number of items in the collection' + } + } + }, Error: { type: :object, properties: {