From f7a1b20d4dfae99665483b4ff862329bb0400c85 Mon Sep 17 00:00:00 2001 From: Joenio Costa Date: Tue, 22 Feb 2011 14:12:58 -0300 Subject: [PATCH] Units of measurement are in the database now --- app/helpers/manage_products_helper.rb | 8 +++----- app/models/environment.rb | 2 ++ app/models/input.rb | 2 ++ app/models/product.rb | 11 +++-------- app/models/unit.rb | 17 +++++++++++++++++ db/migrate/20110221195242_create_units_and_add_reference_to_it_at_products_and_inputs.rb | 26 ++++++++++++++++++++++++++ db/schema.rb | 13 ++++++++++--- features/manage_inputs.feature | 32 +++++++++++++++++--------------- features/manage_products.feature | 5 ++++- features/step_definitions/noosfero_steps.rb | 9 +++++++-- script/sample-products | 7 +++++++ test/factories.rb | 8 ++++++++ test/functional/manage_products_controller_test.rb | 4 ++-- test/unit/environment_test.rb | 8 ++++++++ test/unit/input_test.rb | 7 ++++++- test/unit/manage_products_helper_test.rb | 12 ++++++++++++ test/unit/product_test.rb | 14 +++++++------- test/unit/unit_test.rb | 34 ++++++++++++++++++++++++++++++++++ 18 files changed, 175 insertions(+), 44 deletions(-) create mode 100644 app/models/unit.rb create mode 100644 db/migrate/20110221195242_create_units_and_add_reference_to_it_at_products_and_inputs.rb create mode 100644 test/unit/unit_test.rb diff --git a/app/helpers/manage_products_helper.rb b/app/helpers/manage_products_helper.rb index 1143ae0..5425bc6 100644 --- a/app/helpers/manage_products_helper.rb +++ b/app/helpers/manage_products_helper.rb @@ -242,8 +242,7 @@ module ManageProductsHelper end def select_unit(object) - selected = object.unit.nil? ? '' : object.unit - select(object.class.name.downcase, 'unit', Product::UNITS.map{|unit| [_(unit[0]), unit[0]]}, {:selected => selected, :include_blank => _('Select the unit')}) + collection_select(object.class.name.downcase, :unit_id, environment.units, :id, :singular, {:include_blank => _('Select the unit')}) end def input_icon(input) @@ -263,14 +262,13 @@ module ManageProductsHelper if product_unit.blank? _('Amount used in this product or service') else - _('Amount used by %s of this product or service') % _(product_unit) + _('Amount used by %s of this product or service') % product_unit.singular.downcase end end def display_unit(input) input_amount_used = content_tag('span', input.formatted_amount, :class => 'input-amount-used') return input_amount_used if input.unit.blank? - units = Product::UNITS.find {|unit| unit[0] == input.unit} - n_('1 %{singular_unit}', '%{num} %{plural_unit}', input.amount_used.to_f) % { :num => input_amount_used, :singular_unit => content_tag('span', units[0], :class => 'input-unit'), :plural_unit => content_tag('span', units[1], :class => 'input-unit') } + n_('1 %{singular_unit}', '%{num} %{plural_unit}', input.amount_used.to_f) % { :num => input_amount_used, :singular_unit => content_tag('span', input.unit.singular, :class => 'input-unit'), :plural_unit => content_tag('span', input.unit.plural, :class => 'input-unit') } end end diff --git a/app/models/environment.rb b/app/models/environment.rb index eef1e14..7988154 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -162,6 +162,8 @@ class Environment < ActiveRecord::Base acts_as_accessible + has_many :units, :order => 'position' + def superior_intances [self, nil] end diff --git a/app/models/input.rb b/app/models/input.rb index bf2071e..41ff330 100644 --- a/app/models/input.rb +++ b/app/models/input.rb @@ -7,6 +7,8 @@ class Input < ActiveRecord::Base acts_as_list :scope => :product + belongs_to :unit + include FloatHelper def price_per_unit=(value) diff --git a/app/models/product.rb b/app/models/product.rb index fddac81..a4101c0 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -42,14 +42,9 @@ class Product < ActiveRecord::Base acts_as_mappable - include FloatHelper + belongs_to :unit - UNITS = [ - [N_('unit'), _('units')], - [N_('litre'), _('litres')], - [N_('kilo'), _('kilos')], - [N_('meter'), _('meters')], - ] + include FloatHelper include WhiteListFilter filter_iframes :description, :whitelist => lambda { enterprise && enterprise.environment && enterprise.environment.trusted_sites_for_iframe } @@ -151,7 +146,7 @@ class Product < ActiveRecord::Base end def name_with_unit - unit.blank? ? name : "#{name} - #{_(unit)}" + unit.blank? ? name : "#{name} - #{unit.name.downcase}" end end diff --git a/app/models/unit.rb b/app/models/unit.rb new file mode 100644 index 0000000..a16f3f6 --- /dev/null +++ b/app/models/unit.rb @@ -0,0 +1,17 @@ +class Unit < ActiveRecord::Base + + validates_presence_of :singular + validates_presence_of :plural + + belongs_to :environment + validates_presence_of :environment_id + acts_as_list :scope => :environment + + def name + self.singular + end + def name=(value) + self.singular = value + end + +end diff --git a/db/migrate/20110221195242_create_units_and_add_reference_to_it_at_products_and_inputs.rb b/db/migrate/20110221195242_create_units_and_add_reference_to_it_at_products_and_inputs.rb new file mode 100644 index 0000000..39c58b0 --- /dev/null +++ b/db/migrate/20110221195242_create_units_and_add_reference_to_it_at_products_and_inputs.rb @@ -0,0 +1,26 @@ +class CreateUnitsAndAddReferenceToItAtProductsAndInputs < ActiveRecord::Migration + def self.up + create_table :units do |t| + t.string :singular, :null => false + t.string :plural, :null => false + t.integer :position + t.references :environment, :null => false + end + [:products, :inputs].each do |table_name| + change_table table_name do |t| + t.remove :unit + t.references :unit + end + end + end + + def self.down + drop_table :units + [:products, :inputs].each do |table_name| + change_table table_name do |t| + t.string :unit + t.remove_references :unit + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 8b8c470..73dca8e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20110215153624) do +ActiveRecord::Schema.define(:version => 20110221195242) do create_table "action_tracker", :force => true do |t| t.integer "user_id" @@ -289,11 +289,11 @@ ActiveRecord::Schema.define(:version => 20110215153624) do t.datetime "created_at" t.datetime "updated_at" t.integer "position" - t.string "unit" t.decimal "price_per_unit" t.decimal "amount_used" t.boolean "relevant_to_price", :default => true t.boolean "is_from_solidarity_economy", :default => false + t.integer "unit_id" end create_table "mailing_sents", :force => true do |t| @@ -345,10 +345,10 @@ ActiveRecord::Schema.define(:version => 20110215153624) do t.datetime "updated_at" t.float "lat" t.float "lng" - t.string "unit" t.float "discount" t.boolean "available", :default => true t.boolean "highlighted" + t.integer "unit_id" end add_index "products", ["enterprise_id"], :name => "index_products_on_enterprise_id" @@ -469,6 +469,13 @@ ActiveRecord::Schema.define(:version => 20110215153624) do t.string "thumbnail" end + create_table "units", :force => true do |t| + t.string "singular", :null => false + t.string "plural", :null => false + t.integer "position" + t.integer "environment_id", :null => false + end + create_table "users", :force => true do |t| t.string "login" t.string "email" diff --git a/features/manage_inputs.feature b/features/manage_inputs.feature index aaea208..070e025 100644 --- a/features/manage_inputs.feature +++ b/features/manage_inputs.feature @@ -20,6 +20,10 @@ Feature: manage inputs | owner | category | name | | redemoinho | rock | Abbey Road | And feature "disable_products_for_enterprises" is disabled on environment + And the following units + | singular | plural | + | Meter | Meters | + | Litre | Litres | @selenium Scenario: add first input to a product @@ -110,9 +114,9 @@ Feature: manage inputs And I am logged in as "joaosilva" When I go to Rede Moinho's page of product Abbey Road And I follow "Inputs" - And I should see "Music" + Then I should see "Music" When I follow "Click here to add price and the amount used" - And I should see "Price ($)" + And I should see "Price" And I fill in "Price" with "10.50" And I press "Save" Then I should not see "Save" @@ -126,11 +130,9 @@ Feature: manage inputs When I go to Rede Moinho's page of product Abbey Road And I follow "Inputs" And I follow "Click here to add price and the amount used" - Then I should see "Price ($)" - And I should not see "Price by meter ($)" - When I select "meter" - Then I should see "Price by meter ($)" - And I should not see "Price ($)" + And I should not see "Price by Meter ($)" + When I select "Meter" + Then I should see "Price by Meter ($)" @selenium Scenario: Save all price details of input @@ -143,10 +145,10 @@ Feature: manage inputs And I follow "Click here to add price and the amount used" And I fill in "Amount used" with "2.5" And I fill in "Price" with "11.50" - And I select "meter" + And I select "Meter" And I press "Save" Then I should see "2.5" - And I should see "meter" + And I should see "Meter" And I should not see "$ 11.50" @selenium @@ -160,17 +162,17 @@ Feature: manage inputs And I follow "Click here to add price and the amount used" And I fill in "Amount used" with "2.5" And I fill in "Price" with "11.50" - And I select "meter" + And I select "Meter" And I press "Save" Then I should see "2.5" - And I should see "meter" + And I should see "Meter" When I follow "Edit" within ".input-details" And I fill in "Amount used" with "3.0" And I fill in "Price" with "23.31" - And I select "litre" + And I select "Litre" And I press "Save" Then I should see "3" - And I should see "litre" + And I should see "Litre" @selenium Scenario: Cancel edition of a input @@ -192,7 +194,7 @@ Feature: manage inputs Scenario: Cancel edition of an input then edit again Given the following input | product | category | price_per_unit | unit | - | Abbey Road | music | 10.0 | unit | + | Abbey Road | music | 10.0 | Meter | And I am logged in as "joaosilva" When I go to Rede Moinho's page of product Abbey Road And I follow "Inputs" @@ -200,7 +202,7 @@ Feature: manage inputs And I follow "Cancel" And I follow "Edit" within ".input-details" Then I should see "Amount used" - And I should see "Price by unit" + And I should see "Price by Meter" @selenium Scenario: remove input diff --git a/features/manage_products.feature b/features/manage_products.feature index 50431cb..575ccf4 100644 --- a/features/manage_products.feature +++ b/features/manage_products.feature @@ -467,11 +467,14 @@ Feature: manage products And the following products | owner | category | name | | redemoinho | bicycle | Bike | + And the following units + | singular | plural | + | Kilo | Kilos | And I am logged in as "joaosilva" When I go to Rede Moinho's page of product Bike And I follow "Edit name and unit" And I fill in "product_name" with "Red bicycle" - And I select "kilo" + And I select "Kilo" And I press "Save" Then I should see "Red bicycle - kilo" diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb index 8124bf2..eac3939 100644 --- a/features/step_definitions/noosfero_steps.rb +++ b/features/step_definitions/noosfero_steps.rb @@ -121,7 +121,8 @@ Given /^the following inputs?$/ do |table| data = item.dup product = Product.find_by_name(data.delete("product")) category = Category.find_by_slug(data.delete("category").to_slug) - input = Input.create!(data.merge(:product => product, :product_category => category)) + unit = Unit.find_by_singular(data.delete("unit")) + input = Input.create!(data.merge(:product => product, :product_category => category, :unit => unit)) input.update_attributes!(:position => data['position']) end end @@ -369,4 +370,8 @@ Given /^someone suggested the following article to be published$/ do |table| end end - +Given /^the following units?$/ do |table| + table.hashes.each do |row| + Unit.create!(row.merge(:environment_id => 1)) + end +end diff --git a/script/sample-products b/script/sample-products index 6b36251..3b5abdd 100755 --- a/script/sample-products +++ b/script/sample-products @@ -39,3 +39,10 @@ for certifier in CERTIFIERS print '.' end puts ' done!' + +print "Creating units: " +[['Litre', 'Litres'], ['Kilo', 'Kilos'], ['Meter', 'Meters']].each do |unit| + Unit.create!(:singular => unit[0], :plural => unit[1], :environment => environment) + print '.' +end +puts ' done!' diff --git a/test/factories.rb b/test/factories.rb index 1416b5a..0eb215b 100644 --- a/test/factories.rb +++ b/test/factories.rb @@ -436,4 +436,12 @@ module Noosfero::Factory { :title => name, :body => "my own comment", :article_id => 1 }.merge(params) end + ############################################### + # Unit + ############################################### + + def defaults_for_unit + { :singular => 'Litre', :plural => 'Litres', :environment_id => 1 } + end + end diff --git a/test/functional/manage_products_controller_test.rb b/test/functional/manage_products_controller_test.rb index 614c618..1c86446 100644 --- a/test/functional/manage_products_controller_test.rb +++ b/test/functional/manage_products_controller_test.rb @@ -272,7 +272,7 @@ class ManageProductsControllerTest < Test::Unit::TestCase end should 'show product price when showing product if unit was informed' do - product = fast_create(Product, :name => 'test product', :price => 50.00, :unit => 'unit', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) + product = fast_create(Product, :name => 'test product', :price => 50.00, :unit_id => fast_create(Unit).id, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) get :show, :id => product.id, :profile => @enterprise.identifier assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/ @@ -280,7 +280,7 @@ class ManageProductsControllerTest < Test::Unit::TestCase end should 'show product price when showing product if discount was informed' do - product = fast_create(Product, :name => 'test product', :price => 50.00, :unit => 'unit', :discount => 3.50, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) + product = fast_create(Product, :name => 'test product', :price => 50.00, :unit_id => fast_create(Unit).id, :discount => 3.50, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) get :show, :id => product.id, :profile => @enterprise.identifier assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /List price:/ diff --git a/test/unit/environment_test.rb b/test/unit/environment_test.rb index a76608c..c08ec47 100644 --- a/test/unit/environment_test.rb +++ b/test/unit/environment_test.rb @@ -1108,4 +1108,12 @@ class EnvironmentTest < Test::Unit::TestCase assert_not_includes env.enabled_features.keys, 'feature3' end + should 'has a list of units ordered by position' do + litre = Unit.create!(:singular => 'Litre', :plural => 'Litres', :environment => Environment.default) + meter = Unit.create!(:singular => 'Meter', :plural => 'Meters', :environment => Environment.default) + kilo = Unit.create!(:singular => 'Kilo', :plural => 'Kilo', :environment => Environment.default) + litre.move_to_bottom + assert_equal ["Meter", "Kilo", "Litre"], Environment.default.units.map(&:singular) + end + end diff --git a/test/unit/input_test.rb b/test/unit/input_test.rb index cf4926f..6f9ed41 100644 --- a/test/unit/input_test.rb +++ b/test/unit/input_test.rb @@ -78,7 +78,7 @@ class InputTest < Test::Unit::TestCase end should 'not have price details if only unit is filled' do - input = Input.new(:unit => 'unit') + input = Input.new(:unit => Unit.new) assert !input.has_price_details? end @@ -157,4 +157,9 @@ class InputTest < Test::Unit::TestCase assert_equal '1.00', input.formatted_value(:price_per_unit) end + should 'has relation with unit' do + input = Input.new + assert_kind_of Unit, input.build_unit + end + end diff --git a/test/unit/manage_products_helper_test.rb b/test/unit/manage_products_helper_test.rb index 6c3d7dc..24c7a62 100644 --- a/test/unit/manage_products_helper_test.rb +++ b/test/unit/manage_products_helper_test.rb @@ -137,6 +137,18 @@ class ManageProductsHelperTest < Test::Unit::TestCase assert_equal 'LINK', edit_ui_button('link to edit', {:action => 'add_input', :id => product.id}) end + should 'show unit on label of amount selection' do + input = Input.new() + input.expects(:product).returns(Product.new(:unit => Unit.new(:singular => 'Meter'))) + assert_equal 'Amount used by meter of this product or service', label_amount_used(input) + end + + should 'not show unit on label of amount selection if product has no unit selected' do + input = Input.new() + input.expects(:product).returns(Product.new) + assert_equal 'Amount used in this product or service', label_amount_used(input) + end + protected include NoosferoTestHelper include ActionView::Helpers::TextHelper diff --git a/test/unit/product_test.rb b/test/unit/product_test.rb index 6f4c0b8..de946d4 100644 --- a/test/unit/product_test.rb +++ b/test/unit/product_test.rb @@ -295,11 +295,6 @@ class ProductTest < Test::Unit::TestCase end end - should 'has a list of units' do - assert_kind_of Array, Product::UNITS - assert_includes Product::UNITS.flatten, 'unit' - end - should 'test if name is blank' do product = Product.new assert product.name_is_blank? @@ -309,7 +304,7 @@ class ProductTest < Test::Unit::TestCase product = Product.new assert !product.has_basic_info? - product = Product.new(:unit => 'unit') + product = Product.new(:unit => Unit.new) assert product.has_basic_info? product = Product.new(:price => 1) @@ -348,8 +343,13 @@ class ProductTest < Test::Unit::TestCase should 'format name with unit' do product = Product.new(:name => "My product") assert_equal "My product", product.name_with_unit - product.unit = 'litre' + product.unit = Unit.new(:name => 'litre') assert_equal "My product - litre", product.name_with_unit end + should 'have relation with unit' do + product = Product.new + assert_kind_of Unit, product.build_unit + end + end diff --git a/test/unit/unit_test.rb b/test/unit/unit_test.rb new file mode 100644 index 0000000..186d0ea --- /dev/null +++ b/test/unit/unit_test.rb @@ -0,0 +1,34 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class UnitTest < Test::Unit::TestCase + + should 'require singular name' do + unit = Unit.new; unit.valid? + assert_match /can't be blank/, unit.errors["singular"] + end + + should 'require plural name' do + unit = Unit.new; unit.valid? + assert_match /can't be blank/, unit.errors["plural"] + end + + should 'belongs and require an environment' do + unit = Unit.new; unit.valid? + assert_match /can't be blank/, unit.errors["environment_id"] + unit.environment = Environment.default; unit.valid? + assert_nil unit.errors["environment_id"] + end + + should 'increment position automatically' do + first = Unit.create!(:singular => 'Litre', :plural => 'Litres', :environment => Environment.default) + second = Unit.create!(:singular => 'Meter', :plural => 'Meters', :environment => Environment.default) + assert_equal 1, first.position + assert_equal 2, second.position + end + + should 'has an getter and setter alias to singular field' do + unit = Unit.new(:name => 'Litre') + assert_equal 'Litre', unit.singular + end + +end -- libgit2 0.21.2