require_relative "../test_helper" class ProductTest < ActiveSupport::TestCase def setup super @product_category = fast_create(ProductCategory, :name => 'Products') @profile = fast_create(Enterprise) end should 'validate the presence of enterprise' do p = Product.new assert_raise ActiveRecord::RecordInvalid do p.save! end end should 'return associated enterprise region' do @profile.region = fast_create Region, :name => 'Salvador' @profile.save! p = fast_create(Product, :name => 'test product1', :product_category_id => @product_category.id, :profile_id => @profile.id) assert_equal @profile.region, p.region end should 'create product' do assert_difference 'Product.count' do p = build(Product, :name => 'test product1', :product_category => @product_category, :profile_id => @profile.id) assert p.save end end should 'destroy product' do p = fast_create(Product, :name => 'test product2', :product_category_id => @product_category.id) assert_difference 'Product.count', -1 do p.destroy end end should 'display category name if name is nil' do p = fast_create(Product, :name => nil) p.expects(:category_name).returns('Software') assert_equal 'Software', p.name end should 'display category name if name is blank' do p = fast_create(Product, :name => '') p.expects(:category_name).returns('Software') assert_equal 'Software', p.name end should 'set nil to name if name is equal to category name' do p = fast_create(Product) p.expects(:category_name).returns('Software').at_least_once p.name = 'Software' p.save assert_equal 'Software', p.name assert_equal nil, p[:name] end should 'list recent products' do enterprise = fast_create(Enterprise, :name => "My enterprise", :identifier => 'my-enterprise') Product.delete_all p1 = enterprise.products.create!(:name => 'product 1', :product_category => @product_category) p2 = enterprise.products.create!(:name => 'product 2', :product_category => @product_category) p3 = enterprise.products.create!(:name => 'product 3', :product_category => @product_category) assert_equal [p3, p2, p1], Product.recent end should 'list recent products with limit' do enterprise = fast_create(Enterprise, :name => "My enterprise", :identifier => 'my-enterprise') Product.delete_all p1 = enterprise.products.create!(:name => 'product 1', :product_category => @product_category) p2 = enterprise.products.create!(:name => 'product 2', :product_category => @product_category) p3 = enterprise.products.create!(:name => 'product 3', :product_category => @product_category) assert_equal [p3, p2], Product.recent(2) end should 'save image on create product' do assert_difference 'Product.count' do p = create(Product, :name => 'test product1', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }, :profile_id => @profile.id) assert_equal p.image(true).filename, 'rails.png' end end should 'have same lat and lng of its enterprise' do ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0) prod = ent.products.create!(:name => 'test product', :product_category => @product_category) prod = Product.find(prod.id) assert_equal ent.lat, prod.lat assert_equal ent.lng, prod.lng end should 'update lat and lng of product afer update enterprise' do ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0) prod = ent.products.create!(:name => 'test product', :product_category => @product_category) ent.lat = 45.0; ent.lng = 45.0; ent.save! process_delayed_job_queue prod.reload assert_in_delta 45.0, prod.lat, 0.0001 assert_in_delta 45.0, prod.lng, 0.0001 end should 'provide url' do product = Product.new enterprise = Enterprise.new enterprise.expects(:public_profile_url).returns({}) product.expects(:id).returns(999) product.expects(:profile).returns(enterprise) assert_equal({:controller => 'manage_products', :action => 'show', :id => 999}, product.url) end should 'respond to public? as its enterprise public?' do e1 = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') p1 = fast_create(Product, :name => 'test product 1', :profile_id => e1.id, :product_category_id => @product_category.id) assert p1.public? e1.public_profile = false e1.save!; p1.reload; refute p1.public? end should 'accept prices in american\'s or brazilian\'s currency format' do [ [12.34, 12.34], ["12.34", 12.34], ["12,34", 12.34], ["12.345.678,90", 12345678.90], ["12,345,678.90", 12345678.90], ["12.345.678", 12345678.00], ["12,345,678", 12345678.00] ].each do |input, output| product = build(Product, :price => input) assert_equal output, product.price end end should 'accept discount in american\'s or brazilian\'s currency format' do [ [12.34, 12.34], ["12.34", 12.34], ["12,34", 12.34], ["12.345.678,90", 12345678.90], ["12,345,678.90", 12345678.90], ["12.345.678", 12345678.00], ["12,345,678", 12345678.00] ].each do |input, output| product = build(Product, :discount => input) assert_equal output, product.discount end end should 'strip name with malformed HTML when sanitize' do product = build(Product, :product_category => @product_category) product.name = "

" product.valid? assert_equal @product_category.name, product.name end should 'use name of category when has no name yet' do product = Product.new product.product_category = @product_category product.profile = @profile assert product.valid? assert_equal @product_category.name, product.name end should 'not save without category' do product = build(Product, :name => 'A product without category') product.valid? assert product.errors[:product_category_id.to_s].present? end should 'not save with a invalid category' do category = build(Category, :name => 'Region', :environment => Environment.default) assert_raise ActiveRecord::AssociationTypeMismatch do build(Product, :name => 'Invalid category product', :product_category => category) end end should 'format values to float with 2 decimals' do ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') product = fast_create(Product, :profile_id => ent.id, :price => 12.994, :discount => 1.994) assert_equal "12.99", product.formatted_value(:price) assert_equal "1.99", product.formatted_value(:discount) end should 'calculate price with discount' do ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') product = fast_create(Product, :profile_id => ent.id, :price => 12.994, :discount => 1.994) assert_equal 11.00, product.price_with_discount end should 'calculate price without discount' do ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1') product = fast_create(Product, :profile_id => ent.id, :price => 12.994, :discount => 0) assert_equal product.price, product.price_with_discount end should 'have default image' do product = Product.new assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image end should 'have inputs' do product = Product.new assert_respond_to product, :inputs end should 'return empty array if has no input' do product = Product.new assert product.inputs.empty? end should 'return product inputs' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id) assert_equal [input], product.inputs end should 'destroy inputs when product is removed' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id) services_category = fast_create(ProductCategory, :name => 'Services') input2 = fast_create(Input, :product_id => product.id, :product_category_id => services_category.id) assert_difference 'Input.count', -2 do product.destroy end end should 'test if name is blank' do product = Product.new assert product.name_is_blank? end should 'has basic info if filled unit, price or discount' do product = Product.new refute product.has_basic_info? product = build(Product, :unit => Unit.new) assert product.has_basic_info? product = build(Product, :price => 1) assert product.has_basic_info? product = build(Product, :discount => 1) assert product.has_basic_info? end should 'destroy all qualifiers when save qualifiers list' do product = fast_create(Product) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) product.product_qualifiers.create(:qualifier => fast_create(Qualifier), :certifier => fast_create(Certifier)) assert_equal 3, product.qualifiers.count product.qualifiers_list = [[fast_create(Qualifier).id, fast_create(Certifier).id]] assert_equal 1, product.qualifiers.count end should 'save order of inputs' do product = fast_create(Product) first = create(Input, :product => product, :product_category => fast_create(ProductCategory)) second = create(Input, :product => product, :product_category => fast_create(ProductCategory)) third = create(Input, :product => product, :product_category => fast_create(ProductCategory)) assert_equal [first, second, third], product.inputs product.order_inputs!([second.id, first.id, third.id]) assert_equal [second, first, third], product.inputs(true) end should 'format name with unit' do product = build(Product, :name => "My product") assert_equal "My product", product.name_with_unit product.unit = build(Unit, :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 should 'respond to price details' do product = Product.new assert_respond_to product, :price_details end should 'return total value of inputs' do product = fast_create(Product) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert_equal 50.0, product.inputs_cost end should 'return total value only of inputs relevant to price' do product = fast_create(Product) first_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) second_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) not_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1, :relevant_to_price => false) assert_equal 50.0, product.inputs_cost end should 'return 0 on total value of inputs if has no input' do product = fast_create(Product) assert product.inputs_cost.zero? end should 'know if price is described' do product = fast_create(Product, :price => 30.0) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 1) refute Product.find(product.id).price_described? second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert Product.find(product.id).price_described? end should 'return false on price_described if price of product is not defined' do product = fast_create(Product) assert_equal false, product.price_described? end should 'create price details' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') assert product.price_details.empty? product.update_price_details([{:production_cost_id => cost.id, :price => 10}]) assert_equal 1, Product.find(product.id).price_details.size end should 'update price of a cost on price details' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') cost2 = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) refute product.price_details.empty? product.update_price_details([{:production_cost_id => cost.id, :price => 20}, {:production_cost_id => cost2.id, :price => 30}]) assert_equal 20, product.price_details.find_by_production_cost_id(cost.id).price assert_equal 2, Product.find(product.id).price_details.size end should 'destroy price details if product is removed' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) assert_difference 'PriceDetail.count', -1 do product.destroy end end should 'have production costs' do product = fast_create(Product) cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') product.price_details.create(:production_cost_id => cost.id, :price => 10) assert_equal [cost], Product.find(product.id).production_costs end should 'return production costs from enterprise and environment' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') assert_equal [env_production_cost, ent_production_cost], product.available_production_costs end should 'return all production costs' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') create(PriceDetail, :product => product, :production_cost => env_production_cost, :product => product) assert_equal [env_production_cost, ent_production_cost], product.available_production_costs end should 'return total value of production costs' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') price_detail = create(PriceDetail, :product => product, :production_cost => env_production_cost, :price => 10) input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) assert_equal price_detail.price + input.cost, product.total_production_cost end should 'return inputs cost as total value of production costs if has no price details' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) assert_equal input.cost, product.total_production_cost end should 'return 0 on total production cost if has no input and price details' do product = fast_create(Product) assert product.total_production_cost.zero? end should 'format inputs cost values to float with 2 decimals' do ent = fast_create(Enterprise) product = fast_create(Product, :profile_id => ent.id) first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) assert_equal "50.00", product.formatted_value(:inputs_cost) end should 'return 0 on price_description_percentage by default' do assert_equal 0, Product.new.price_description_percentage end should 'return 0 on price_description_percentage if price is 0' do product = fast_create(Product, :price => 0) assert_equal 0, product.price_description_percentage end should 'return 0 on price_description_percentage if price is not defined' do product = fast_create(Product) assert_equal 0, product.price_description_percentage end should 'return 0 on price_description_percentage if total_production_cost is 0' do product = fast_create(Product, :price => 50) assert_equal 0, product.price_description_percentage end should 'return solidarity percentage from inputs' do prod = fast_create(Product, :name => 'test product1', :product_category_id => @product_category.id, :profile_id => @profile.id) assert_equal 0, prod.percentage_from_solidarity_economy.first prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => false) assert_equal 0, prod.percentage_from_solidarity_economy.first prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true) assert_equal 50, prod.percentage_from_solidarity_economy.first prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => false) assert_equal 25, prod.percentage_from_solidarity_economy.first prod = fast_create(Product, :name => 'test product1', :product_category_id => @product_category.id, :profile_id => @profile.id) prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true) prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true) prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true) prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => false) assert_equal 75, prod.percentage_from_solidarity_economy.first prod = fast_create(Product, :name => 'test product', :product_category_id => @product_category.id, :profile_id => @profile.id) prod.inputs.create!(:product_id => prod.id, :product_category_id => @product_category.id, :amount_used => 10, :price_per_unit => 10, :is_from_solidarity_economy => true) assert_equal 100, prod.percentage_from_solidarity_economy.first end should 'delegate region info to enterprise' do enterprise = fast_create(Enterprise) Enterprise.any_instance.expects(:region) Enterprise.any_instance.expects(:region_id) product = fast_create(Product, :profile_id => enterprise.id) product.region product.region_id end should 'delegate environment info to enterprise' do enterprise = fast_create(Enterprise) Enterprise.any_instance.expects(:environment) Enterprise.any_instance.expects(:environment_id) product = fast_create(Product, :profile_id => enterprise.id) product.environment product.environment_id end should 'return more recent products' do Product.destroy_all prod1 = create(Product, :name => 'Damaged LP', :profile_id => @profile.id, :product_category_id => @product_category.id) prod2 = create(Product, :name => 'Damaged CD', :profile_id => @profile.id, :product_category_id => @product_category.id) prod3 = create(Product, :name => 'Damaged DVD', :profile_id => @profile.id, :product_category_id => @product_category.id) prod1.update_attribute :created_at, Time.now-2.days prod2.update_attribute :created_at, Time.now-1.days prod3.update_attribute :created_at, Time.now assert_equal [prod3, prod2, prod1], Product.more_recent end should 'return products from a category' do pc1 = ProductCategory.create!(:name => 'PC1', :environment => Environment.default) pc2 = ProductCategory.create!(:name => 'PC2', :environment => Environment.default) pc3 = ProductCategory.create!(:name => 'PC3', :environment => Environment.default, :parent => pc1) p1 = fast_create(Product, :product_category_id => pc1) p2 = fast_create(Product, :product_category_id => pc1) p3 = fast_create(Product, :product_category_id => pc2) p4 = fast_create(Product, :product_category_id => pc3) products = Product.from_category(pc1) assert_includes products, p1 assert_includes products, p2 assert_not_includes products, p3 assert_includes products, p4 end should 'not crash if nil is passed to from_category' do assert_nothing_raised do Product.from_category(nil) end end should 'return from_category scope untouched if passed nil' do enterprise = fast_create(Enterprise) p1 = fast_create(Product, :profile_id => enterprise.id) p2 = fast_create(Product, :profile_id => enterprise.id) p3 = fast_create(Product, :profile_id => enterprise.id) products = enterprise.products.from_category(nil) assert_includes products, p1 assert_includes products, p2 assert_includes products, p3 end should 'fetch products from organizations that are visible for a user' do person = create_user('some-person').person admin = create_user('some-admin').person env_admin = create_user('env-admin').person env = Environment.default e1 = fast_create(Enterprise, :public_profile => true , :visible => true) p1 = fast_create(Product, :profile_id => e1.id) e1.affiliate(admin, Profile::Roles.admin(env.id)) e1.affiliate(person, Profile::Roles.member(env.id)) e2 = fast_create(Enterprise, :public_profile => true , :visible => true) p2 = fast_create(Product, :profile_id => e2.id) e3 = fast_create(Enterprise, :public_profile => false, :visible => true) p3 = fast_create(Product, :profile_id => e3.id) e4 = fast_create(Enterprise, :public_profile => false, :visible => true) p4 = fast_create(Product, :profile_id => e4.id) e4.affiliate(admin, Profile::Roles.admin(env.id)) e4.affiliate(person, Profile::Roles.member(env.id)) e5 = fast_create(Enterprise, :public_profile => true, :visible => false) p5 = fast_create(Product, :profile_id => e5.id) e5.affiliate(admin, Profile::Roles.admin(env.id)) e5.affiliate(person, Profile::Roles.member(env.id)) e6 = fast_create(Enterprise, :enabled => false, :visible => true) p6 = fast_create(Product, :profile_id => e6.id) e6.affiliate(admin, Profile::Roles.admin(env.id)) e7 = fast_create(Enterprise, :public_profile => false, :visible => false) p7 = fast_create(Product, :profile_id => e7.id) Environment.default.add_admin(env_admin) products_person = Product.visible_for_person(person) products_admin = Product.visible_for_person(admin) products_env_admin = Product.visible_for_person(env_admin) assert_includes products_person, p1 assert_includes products_admin, p1 assert_includes products_env_admin, p1 assert_includes products_person, p2 assert_includes products_env_admin, p2 assert_not_includes products_person, p3 assert_includes products_env_admin, p3 assert_includes products_person, p4 assert_includes products_admin, p4 assert_includes products_env_admin, p4 assert_not_includes products_person, p5 assert_includes products_admin, p5 assert_includes products_env_admin, p5 assert_not_includes products_person, p6 assert_includes products_admin, p6 assert_includes products_env_admin, p6 assert_not_includes products_person, p7 assert_includes products_env_admin, p7 end end