Commit 932d74f8b65c6cad2ed4db8f009d8237d604180c

Authored by Daniela Feitosa
Committed by Joenio Costa
1 parent 56d303cc

Added structure to add inputs to a product

  * Created a new table inputs
  * For each consumption of a profile was created an input to each product of the profile
  * Removed consumptions table

(ActionItem1435)
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -18,7 +18,6 @@ class ManageProductsController < ApplicationController
18 18  
19 19 def index
20 20 @products = @profile.products
21   - @consumptions = @profile.consumptions
22 21 end
23 22  
24 23 def show
... ... @@ -38,7 +37,7 @@ class ManageProductsController < ApplicationController
38 37 end
39 38  
40 39 def new
41   - @product = @profile.products.build(params[:product])
  40 + @product = @profile.products.build(:product_category_id => params[:selected_category_id])
42 41 @category = @product.product_category
43 42 @categories = ProductCategory.top_level_for(environment)
44 43 @level = 0
... ... @@ -75,12 +74,25 @@ class ManageProductsController < ApplicationController
75 74 @edit = true
76 75 @level = @category.level
77 76 if request.post?
78   - begin
79   - @product.update_attributes!(params[:product])
  77 + if @product.update_attributes(:product_category_id => params[:selected_category_id])
80 78 render :partial => 'shared/redirect_via_javascript',
81 79 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
82   - rescue Exception => e
83   - flash[:notice] = _('Could not update the product')
  80 + else
  81 + render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' }
  82 + end
  83 + end
  84 + end
  85 +
  86 + def add_input
  87 + @product = @profile.products.find(params[:id])
  88 + @input = @product.inputs.build
  89 + @categories = ProductCategory.top_level_for(environment)
  90 + @level = 0
  91 + if request.post?
  92 + if @input.update_attributes(:product_category_id => params[:selected_category_id])
  93 + render :partial => 'shared/redirect_via_javascript',
  94 + :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
  95 + else
84 96 render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' }
85 97 end
86 98 end
... ...
app/helpers/manage_products_helper.rb
... ... @@ -89,8 +89,8 @@ module ManageProductsHelper
89 89 )
90 90 end
91 91  
92   - def categories_container(field_id_html, categories_selection_html, hierarchy_html = '')
93   - field_id_html +
  92 + def categories_container(categories_selection_html, hierarchy_html = '')
  93 + hidden_field_tag('selected_category_id') +
94 94 content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
95 95 content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
96 96 end
... ... @@ -108,7 +108,13 @@ module ManageProductsHelper
108 108 end
109 109 end
110 110  
111   - def edit_product_link(product, field, label, html_options = {})
  111 + def edit_product_link(field, label, url, html_options = {})
  112 + return '' unless (user && user.has_permission?('manage_products', profile))
  113 + options = html_options.merge(:id => "link-edit-#{field}")
  114 + link_to(label, url, options)
  115 + end
  116 +
  117 + def edit_product_link_to_remote(product, field, label, html_options = {})
112 118 return '' unless (user && user.has_permission?('manage_products', profile))
113 119 options = html_options.merge(:id => 'link-edit-product-' + field)
114 120  
... ... @@ -124,12 +130,18 @@ module ManageProductsHelper
124 130 if html_options.has_key?(:class)
125 131 the_class << ' ' << html_options[:class]
126 132 end
127   - edit_product_link(product, field, label, html_options.merge(:class => the_class))
  133 + edit_product_link_to_remote(product, field, label, html_options.merge(:class => the_class))
128 134 end
129 135  
130   - def edit_product_ui_button(product, field, label, html_options = {})
  136 + def edit_product_ui_button(field, label, url, html_options = {})
131 137 return '' unless (user && user.has_permission?('manage_products', profile))
132 138 options = html_options.merge(:id => 'edit-product-button-ui-' + field)
  139 + ui_button(label, url, options)
  140 + end
  141 +
  142 + def edit_product_ui_button_to_remote(product, field, label, html_options = {})
  143 + return '' unless (user && user.has_permission?('manage_products', profile))
  144 + options = html_options.merge(:id => 'edit-product-remote-button-ui-' + field)
133 145  
134 146 ui_button_to_remote(label,
135 147 {:update => "product-#{field}",
... ... @@ -146,12 +158,6 @@ module ManageProductsHelper
146 158 end
147 159 end
148 160  
149   - def edit_product_category_link(product, html_options = {})
150   - return '' unless (user && user.has_permission?('manage_products', profile))
151   - options = html_options.merge(:id => 'link-edit-product-category')
152   - link_to(_('Change category'), { :action => 'edit_category', :id => product.id}, options)
153   - end
154   -
155 161 def float_to_currency(value)
156 162 number_to_currency(value, :unit => environment.currency_unit, :separator => environment.currency_separator, :delimiter => environment.currency_delimiter, :format => "%u %n")
157 163 end
... ...
app/models/consumption.rb
... ... @@ -1,9 +0,0 @@
1   -class Consumption < ActiveRecord::Base
2   - belongs_to :profile
3   - belongs_to :product_category
4   -
5   - validates_uniqueness_of :product_category_id, :scope => :profile_id
6   -
7   - xss_terminate :only => [ :aditional_specifications ], :on => 'validation'
8   -
9   -end
app/models/input.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class Input < ActiveRecord::Base
  2 + belongs_to :product
  3 + belongs_to :product_category
  4 +
  5 + validates_presence_of :product
  6 + validates_presence_of :product_category
  7 +end
... ...
app/models/product.rb
... ... @@ -4,9 +4,11 @@ class Product &lt; ActiveRecord::Base
4 4 has_many :product_categorizations
5 5 has_many :product_qualifiers
6 6 has_many :qualifiers, :through => :product_qualifiers
  7 + has_many :inputs, :dependent => :destroy
7 8  
8 9 validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true
9   - validates_presence_of :product_category
  10 + validates_presence_of :product_category_id
  11 + validates_associated :product_category
10 12  
11 13 validates_numericality_of :price, :allow_nil => true
12 14 validates_numericality_of :discount, :allow_nil => true
... ...
app/models/product_category.rb
1 1 class ProductCategory < Category
2 2 has_many :products
3   - has_many :consumptions
4   - has_many :consumers, :through => :consumptions, :source => :profile
  3 + has_many :inputs
5 4  
6 5 def all_products
7 6 Product.find(:all, :conditions => { :product_category_id => (all_children << self).map(&:id) })
... ...
app/models/profile.rb
... ... @@ -120,9 +120,6 @@ class Profile &lt; ActiveRecord::Base
120 120  
121 121 acts_as_having_image
122 122  
123   - has_many :consumptions
124   - has_many :consumed_product_categories, :through => :consumptions, :source => :product_category
125   -
126 123 has_many :tasks, :dependent => :destroy, :as => 'target'
127 124  
128 125 has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name'
... ...
app/views/manage_products/_categories_for_selection.rhtml
... ... @@ -2,7 +2,7 @@
2 2  
3 3 <% javascript_tag do %>
4 4 jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
5   - $('product_product_category_id').value = <%= @category && @category.id %>
  5 + $('selected_category_id').value = <%= @category && @category.id %>
6 6 $('hierarchy_navigation').update('<%= escape_javascript(hierarchy_category_navigation(@category, :make_links => true)) %>')
7 7 toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, $('save_and_continue'))
8 8 <% end %>
... ...
app/views/manage_products/_display_category.rhtml
1 1 <div id='display-product-category'>
2 2 <p><%= hierarchy_category_navigation(@product.product_category, :make_links => false)%></p>
3   - <%= edit_product_category_link(@product) %>
  3 + <%= edit_product_link('product-category', _('Change category'), { :action => 'edit_category', :id => @product.id}) %>
4 4 </div>
... ...
app/views/manage_products/_display_image.rhtml
... ... @@ -2,4 +2,4 @@
2 2 <%= image_tag (@product.reload.image ? @product.image.public_filename : @product.default_image('thumb')), :class => 'product-pic' %>
3 3 </div>
4 4  
5   -<%= edit_product_link(@product, 'image', _('Change image')) %>
  5 +<%= edit_product_link_to_remote(@product, 'image', _('Change image')) %>
... ...
app/views/manage_products/_display_info.rhtml
... ... @@ -9,6 +9,6 @@
9 9 <% if @product.has_basic_info? %>
10 10 <%= edit_product_button(@product, 'info', _('Edit basic information')) %>
11 11 <% else %>
12   - <%= edit_product_ui_button(@product, 'info', _('Add description, price and other basic information'), :title => _('Click here to add description, price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers'), 'data-primary-icon' => 'ui-icon-pencil', 'data-secondary-icon' => 'ui-icon-triangle-1-s') %>
13   - <%= javascript_tag("render_jquery_ui_buttons('edit-product-button-ui-info')") %>
  12 + <%= edit_product_ui_button_to_remote(@product, 'info', _('Add description, price and other basic information'), :title => _('Click here to add description, price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers'), 'data-primary-icon' => 'ui-icon-pencil', 'data-secondary-icon' => 'ui-icon-triangle-1-s') %>
  13 + <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-info')") %>
14 14 <% end%>
... ...
app/views/manage_products/_display_inputs.rhtml 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<%= edit_product_ui_button('inputs', _('Add the inputs used by this product'), {:action => 'add_input', :id => @product.id}, 'data-primary-icon' => 'ui-icon-pencil', 'data-secondary-icon' => 'ui-icon-triangle-1-s') %>
  2 +<%= javascript_tag("render_jquery_ui_buttons('edit-product-button-ui-inputs')") %>
... ...
app/views/manage_products/_display_name.rhtml
1 1 <div id='display-product-name'>
2 2 <h2><%= @product.reload.name %></h2>
3   - <%= edit_product_link(@product, 'name', _('Edit name')) %>
  3 + <%= edit_product_link_to_remote(@product, 'name', _('Edit name')) %>
4 4 </div>
5 5  
... ...
app/views/manage_products/add_input.rhtml 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +<div class=product-category-hierarchy>
  2 + <%= hierarchy_category_navigation(@product.product_category, :make_links => false)%>
  3 +</div>
  4 +
  5 +<div id="category-product-edition">
  6 +
  7 + <h2><%= @product.name %></h2>
  8 +
  9 + <div id='request_result_message' style='display: none'></div>
  10 +
  11 + <% remote_form_for(@input,
  12 + :loading => "open_loading('#{ _('loading...') }')",
  13 + :update => "request_result_message",
  14 + :url => {:action => 'add_input', :id => @product, :field => 'category'},
  15 + :html => {:method => 'post', :id => 'category_form'}) do |f| %>
  16 +
  17 + <h3><%= _('Choose an input to this product:') %></h3>
  18 +
  19 + <%= categories_container(select_for_new_category) %>
  20 +
  21 + <div id='categories_selection_actionbar'>
  22 + <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
  23 + <span id='save_and_continue_wrapper'>
  24 + <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
  25 + <span class='tooltip' id='save_and_continue_disabled_tooltip'>
  26 + <%= ui_icon('ui-icon-alert') %>
  27 + <%= _('This category does not allow registration of products, select a more specific category') %>
  28 + </span>
  29 + </span>
  30 + </div>
  31 +
  32 + <% end %>
  33 +</div>
... ...
app/views/manage_products/edit_category.rhtml
1 1 <div class=product-category-hierarchy>
2   - <%= hierarchy_category_navigation(@product.product_category, :make_links => false)%>
  2 + <%= hierarchy_category_navigation(@category, :make_links => false)%>
3 3 </div>
4 4  
5 5 <div id="category-product-edition">
... ... @@ -8,16 +8,15 @@
8 8  
9 9 <div id='request_result_message' style='display: none'></div>
10 10  
11   - <% remote_form_for(:product, @product,
  11 + <% remote_form_for(@product,
12 12 :loading => "open_loading('#{ _('loading...') }')",
13   - :loaded => "close_loading()",
14 13 :update => "request_result_message",
15   - :url => {:action => 'edit_category', :id => @product, :field => 'category'},
16   - :html => {:method => 'post', :id => 'product_category_form'}) do |f| %>
  14 + :url => {:action => 'edit_category', :id => @product},
  15 + :html => {:method => 'post', :id => 'category_form'}) do |f| %>
17 16  
18 17 <h3><%= _('Edit category of this product:') %></h3>
19 18  
20   - <%= categories_container(f.hidden_field('product_category_id'), selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true)) %>
  19 + <%= categories_container(selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true)) %>
21 20  
22 21 <div id='categories_selection_actionbar'>
23 22 <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
... ...
app/views/manage_products/new.rhtml
... ... @@ -6,11 +6,11 @@
6 6 :loading => "open_loading('#{ _('loading...') }')",
7 7 :update => "request_result_message",
8 8 :url => {:action => 'new'},
9   - :html => {:method => 'post', :id => 'product_category_form'} do |f| %>
  9 + :html => {:method => 'post', :id => 'category_form'} do |f| %>
10 10  
11 11 <h3><%= _('Select the category of the new product or service') %></h3>
12 12  
13   - <%= categories_container(f.hidden_field('product_category_id'), select_for_new_category) %>
  13 + <%= categories_container(select_for_new_category) %>
14 14  
15 15 <div id='categories_selection_actionbar'>
16 16 <%= button :back, _('Back to the product listing'), :action => 'index' %>
... ...
app/views/manage_products/show.rhtml
... ... @@ -17,6 +17,10 @@
17 17 <%= render :partial => 'manage_products/display_info', :locals => {:product => @product} %>
18 18 </div>
19 19  
  20 + <div id='product-inputs'>
  21 + <%= render :partial => 'manage_products/display_inputs', :locals => {:product => @product} %>
  22 + </div>
  23 +
20 24 </div>
21 25 </div>
22 26  
... ...
db/migrate/20100719142230_create_inputs.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateInputs < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :inputs do |t|
  4 + t.references :product, :null => false
  5 + t.references :product_category, :null => false
  6 +
  7 + t.timestamps
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :inputs
  13 + end
  14 +end
... ...
db/migrate/20100719142737_move_consumptions_to_inputs_and_destroy_consumptions.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class MoveConsumptionsToInputsAndDestroyConsumptions < ActiveRecord::Migration
  2 + def self.up
  3 + select_all('SELECT product_category_id, profile_id FROM consumptions').each do |consumption|
  4 + Profile.find(consumption['profile_id']).products.each do |product|
  5 + Input.create(:product_category_id => consumption['product_category_id'], :product_id => product.id)
  6 + end
  7 + end
  8 + drop_table :consumptions
  9 + end
  10 +
  11 + def self.down
  12 + say 'Warning: This migration cant recover data from old cunsumptions table'
  13 + create_table :consumptions do |t|
  14 + t.column :product_category_id, :integer
  15 + t.column :profile_id, :integer
  16 + t.column :aditional_specifications, :text
  17 + end
  18 + end
  19 +end
... ...
db/schema.rb
... ... @@ -160,12 +160,6 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do
160 160 t.datetime "created_at"
161 161 end
162 162  
163   - create_table "consumptions", :force => true do |t|
164   - t.integer "product_category_id"
165   - t.integer "profile_id"
166   - t.text "aditional_specifications"
167   - end
168   -
169 163 create_table "domains", :force => true do |t|
170 164 t.string "name"
171 165 t.string "owner_type"
... ... @@ -228,6 +222,13 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do
228 222 t.integer "height"
229 223 end
230 224  
  225 + create_table "inputs", :force => true do |t|
  226 + t.integer "product_category_id", :null => false
  227 + t.integer "product_id", :null => false
  228 + t.datetime "created_at"
  229 + t.datetime "updated_at"
  230 + end
  231 +
231 232 create_table "product_categorizations", :force => true do |t|
232 233 t.integer "category_id"
233 234 t.integer "product_id"
... ...
features/manage_products.feature
... ... @@ -351,3 +351,37 @@ Feature: manage products
351 351 When I follow "Cancel"
352 352 Then I should see "A new red bicycle"
353 353 And I should be on Rede Moinho's page of product Bike
  354 +
  355 + @selenium
  356 + Scenario: add an input to a product
  357 + Given the following product_category
  358 + | name |
  359 + | Food |
  360 + And the following product_categories
  361 + | name | parent |
  362 + | Cake | food |
  363 + | Sugar | food |
  364 + And the following products
  365 + | owner | category | name |
  366 + | redemoinho | cake | Chocolate cake |
  367 + And I am logged in as "joaosilva"
  368 + When I go to Rede Moinho's page of product Chocolate cake
  369 + And I follow "Add the inputs used by this product"
  370 + And I select "Food »"
  371 + And I select "Sugar"
  372 + And I press "Save and continue"
  373 + Then I should see "Sugar"
  374 +
  375 + @selenium
  376 + Scenario: cancel addition of a product input
  377 + Given the following product_category
  378 + | name |
  379 + | Food |
  380 + And the following products
  381 + | owner | category | name |
  382 + | redemoinho | food | Cake |
  383 + And I am logged in as "joaosilva"
  384 + When I go to Rede Moinho's page of product Cake
  385 + And I follow "Add the inputs used by this product"
  386 + When I follow "Back to product"
  387 + Then I should see "Cake"
... ...
public/stylesheets/application.css
... ... @@ -2613,7 +2613,7 @@ div#activation_enterprise div {
2613 2613 list-style: none;
2614 2614 }
2615 2615  
2616   -#edit-product-button-ui-info {
  2616 +#edit-product-remote-button-ui-info {
2617 2617 margin-top: 40px;
2618 2618 }
2619 2619  
... ... @@ -2655,6 +2655,11 @@ div#activation_enterprise div {
2655 2655 #product-qualifiers-list .product-certifier-title {
2656 2656 margin-right: 20px;
2657 2657 }
  2658 +
  2659 +#edit-product-button-ui-inputs {
  2660 + margin-top: 20px;
  2661 +}
  2662 +
2658 2663 /* ==> public/stylesheets/controller_cms.css <== */
2659 2664  
2660 2665 .controller-cms #article_types li {
... ... @@ -3142,7 +3147,7 @@ h1#agenda-title {
3142 3147  
3143 3148 /* ==> public/stylesheets/controller_manage_products.css <== */
3144 3149  
3145   -#product_category_form {
  3150 +#category_form {
3146 3151 border: 1px solid #AABB88;
3147 3152 -moz-border-radius: 5px;
3148 3153 -webkit-border-radius: 5px;
... ...
test/factories.rb
... ... @@ -330,4 +330,12 @@ module Noosfero::Factory
330 330 { :name => 'Product ' + factory_num_seq.to_s }
331 331 end
332 332  
  333 + ###############################################
  334 + # Input
  335 + ###############################################
  336 +
  337 + def defaults_for_input
  338 + { }
  339 + end
  340 +
333 341 end
... ...
test/fixtures/consumptions.yml
... ... @@ -1,5 +0,0 @@
1   -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2   -one:
3   - id: 1
4   -two:
5   - id: 2
test/functional/manage_products_controller_test.rb
... ... @@ -50,7 +50,7 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
50 50  
51 51 should "create new product" do
52 52 assert_difference Product, :count do
53   - post 'new', :profile => @enterprise.identifier, :product => {:name => 'test product', :product_category_id => @product_category.id}
  53 + post 'new', :profile => @enterprise.identifier, :product => {:name => 'test product'}, :selected_category_id => @product_category.id
54 54 assert assigns(:product)
55 55 assert !assigns(:product).new_record?
56 56 end
... ... @@ -117,17 +117,16 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
117 117 end
118 118  
119 119 should "not edit to invalid parameters" do
120   - product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
121   - post 'edit_category', :profile => @enterprise.identifier, :product => {:product_category => nil}, :id => product.id
  120 + product = fast_create(Product, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
  121 + post 'edit_category', :profile => @enterprise.identifier, :selected_category_id => nil, :id => product.id
122 122 assert_response :success
123   - assert assigns(:product)
124   - assert ! assigns(:product).valid?
  123 + assert_template 'shared/_dialog_error_messages'
125 124 end
126 125  
127 126 should "destroy product" do
128   - p = @enterprise.products.create!(:name => 'test product', :product_category => @product_category)
  127 + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
129 128 assert_difference Product, :count, -1 do
130   - post 'destroy', :profile => @enterprise.identifier, :id => p.id
  129 + post 'destroy', :profile => @enterprise.identifier, :id => product.id
131 130 assert_response :redirect
132 131 assert_redirected_to :action => 'index'
133 132 assert assigns(:product)
... ... @@ -136,10 +135,10 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
136 135 end
137 136  
138 137 should "fail to destroy product" do
139   - p = @enterprise.products.create!(:name => 'test product', :product_category => @product_category)
  138 + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
140 139 Product.any_instance.stubs(:destroy).returns(false)
141 140 assert_no_difference Product, :count do
142   - post 'destroy', :profile => @enterprise.identifier, :id => p.id
  141 + post 'destroy', :profile => @enterprise.identifier, :id => product.id
143 142 assert_response :redirect
144 143 assert_redirected_to :action => 'show'
145 144 assert assigns(:product)
... ... @@ -159,20 +158,20 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
159 158 category1 = fast_create(ProductCategory, :name => 'Category 1')
160 159 category2 = fast_create(ProductCategory, :name => 'Category 2', :parent_id => category1)
161 160 assert_difference Product, :count do
162   - post 'new', :profile => @enterprise.identifier, :product => { :name => 'test product', :product_category_id => category2.id }
  161 + post 'new', :profile => @enterprise.identifier, :product => { :name => 'test product' }, :selected_category_id => category2.id
163 162 assert_equal category2, assigns(:product).product_category
164 163 end
165 164 end
166 165  
167 166 should 'filter html from name of product' do
168 167 category = fast_create(ProductCategory, :name => 'Category 1')
169   - post 'new', :profile => @enterprise.identifier, :product => { :name => "<b id='html_name'>name bold</b>", :product_category_id => category.id }
  168 + post 'new', :profile => @enterprise.identifier, :product => { :name => "<b id='html_name'>name bold</b>" }, :selected_category_id => category.id
170 169 assert_sanitized assigns(:product).name
171 170 end
172 171  
173   - should 'filter html with whit list from description of product' do
174   - category = fast_create(ProductCategory, :name => 'Category 1')
175   - post 'new', :profile => @enterprise.identifier, :product => { :name => 'name', :description => "<b id='html_descr'>descr bold</b>", :product_category_id => category.id }
  172 + should 'filter html with white list from description of product' do
  173 + product = fast_create(Product, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
  174 + post 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'info', :product => { :name => 'name', :description => "<b id='html_descr'>descr bold</b>" }
176 175 assert_equal "<b>descr bold</b>", assigns(:product).description
177 176 end
178 177  
... ... @@ -235,7 +234,7 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
235 234  
236 235 should 'render redirect_via_javascript template after save' do
237 236 assert_difference Product, :count do
238   - post :new, :profile => @enterprise.identifier, :product => { :name => 'Invalid product', :product_category_id => @product_category.id }
  237 + post :new, :profile => @enterprise.identifier, :product => { :name => 'Invalid product' }, :selected_category_id => @product_category.id
239 238 assert_template 'shared/_redirect_via_javascript'
240 239 end
241 240 end
... ... @@ -273,25 +272,37 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
273 272 end
274 273  
275 274 should 'show product price when showing product if unit was informed' do
276   - prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :unit => 'unit', :product_category => @product_category)
277   - get :show, :id => prod.id, :profile => @enterprise.identifier
  275 + product = fast_create(Product, :name => 'test product', :price => 50.00, :unit => 'unit', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
  276 + get :show, :id => product.id, :profile => @enterprise.identifier
278 277  
279 278 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/
  279 + assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
280 280 end
281 281  
282 282 should 'show product price when showing product if discount was informed' do
283   - prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :discount => 3.50, :unit => 'unit', :product_category => @product_category)
284   - get :show, :id => prod.id, :profile => @enterprise.identifier
  283 + 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)
  284 + get :show, :id => product.id, :profile => @enterprise.identifier
285 285  
286 286 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /List price:/
  287 + assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
287 288 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /On sale:/
  289 + assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 46.50'
288 290 end
289 291  
290 292 should 'not show product price when showing product if unit not informed' do
291   - prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category)
292   - get :show, :id => prod.id, :profile => @enterprise.identifier
  293 + product = fast_create(Product, :name => 'test product', :price => 50.00, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
  294 + get :show, :id => product.id, :profile => @enterprise.identifier
293 295  
294   - assert_no_tag :tag => 'span', :attributes => { :class => 'product_price' }, :content => /Price:/
  296 + assert_no_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/
  297 + assert_no_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
  298 + end
  299 +
  300 + should 'display button to add input when product has no input' do
  301 + product = fast_create(Product, :name => 'test product', :enterprise_id => @enterprise.id, :product_category_id => @product_category.id)
  302 + get :show, :id => product.id, :profile => @enterprise.identifier
  303 +
  304 + assert_tag :tag => 'div', :attributes => { :id => 'product-inputs'},
  305 + :descendant => {:tag => 'a', :attributes => { :id => 'edit-product-button-ui-inputs' }, :content => 'Add the inputs used by this product'}
295 306 end
296 307  
297 308 end
... ...
test/unit/consumption_test.rb
... ... @@ -1,14 +0,0 @@
1   -require File.dirname(__FILE__) + '/../test_helper'
2   -
3   -class ConsumptionTest < Test::Unit::TestCase
4   - fixtures :consumptions
5   -
6   - should 'escape malformed html tags' do
7   - consumption = Consumption.new
8   - consumption.aditional_specifications = "<h1 Malformed >> html >< tag"
9   - consumption.valid?
10   -
11   - assert_no_match /[<>]/, consumption.aditional_specifications
12   - end
13   -
14   -end
test/unit/input_test.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class InputTest < Test::Unit::TestCase
  4 +
  5 + should 'require product_category' do
  6 + product_category = fast_create(ProductCategory, :name => 'Products')
  7 +
  8 + input = Input.new
  9 + input.valid?
  10 + assert input.errors.invalid?(:product_category)
  11 +
  12 + input.product_category = product_category
  13 + input.valid?
  14 + assert !input.errors.invalid?(:product_category)
  15 + end
  16 +
  17 + should 'require product' do
  18 + product_category = fast_create(ProductCategory, :name => 'Products')
  19 + product = fast_create(Product, :name => 'Computer', :product_category_id => product_category.id)
  20 +
  21 + input = Input.new
  22 + input.valid?
  23 + assert input.errors.invalid?(:product)
  24 +
  25 + input.product = product
  26 + input.valid?
  27 + assert !input.errors.invalid?(:product)
  28 + end
  29 +
  30 +end
... ...
test/unit/manage_products_helper_test.rb
... ... @@ -55,7 +55,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
55 55 @controller.expects(:profile).returns(mock)
56 56 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
57 57 product = fast_create(Product, :product_category_id => category.id)
58   - assert_equal '', edit_product_link(product, 'field', 'link to edit')
  58 + assert_equal '', edit_product_link_to_remote(product, 'field', 'link to edit')
59 59 end
60 60  
61 61 should 'display link to edit product when user has permission' do
... ... @@ -69,7 +69,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
69 69  
70 70 expects(:link_to_remote).with('link to edit', {:update => "product-name", :url => {:controller => 'manage_products', :action => 'edit', :id => product.id, :field => 'name'}, :method => :get}, anything).returns('LINK')
71 71  
72   - assert_equal 'LINK', edit_product_link(product, 'name', 'link to edit')
  72 + assert_equal 'LINK', edit_product_link_to_remote(product, 'name', 'link to edit')
73 73 end
74 74  
75 75 should 'not display link to edit product category when user does not have permission' do
... ... @@ -80,7 +80,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
80 80 @controller.expects(:profile).returns(mock)
81 81 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
82 82 product = fast_create(Product, :product_category_id => category.id)
83   - assert_equal '', edit_product_category_link(product)
  83 + assert_equal '', edit_product_link('product-category', 'link to edit category', { :action => 'edit_category', :id => product.id })
84 84 end
85 85  
86 86 should 'display link to edit product category when user has permission' do
... ... @@ -92,7 +92,49 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
92 92 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
93 93 product = fast_create(Product, :product_category_id => category.id)
94 94  
95   - assert_tag_in_string edit_product_category_link(product), {:tag => 'a', :content => 'Change category'}
  95 + expects(:link_to).with('link to edit category', { :action => 'edit_category', :id => product.id }, {:id => 'link-edit-product-category'} ).returns('LINK')
  96 +
  97 + assert_equal 'LINK', edit_product_link('product-category', 'link to edit category', { :action => 'edit_category', :id => product.id })
  98 + end
  99 +
  100 + should 'not display ui_button to edit product when user does not have permission' do
  101 + user = mock
  102 + user.expects(:has_permission?).with(anything, anything).returns(false)
  103 + @controller = mock
  104 + @controller.expects(:user).returns(user).at_least_once
  105 + @controller.expects(:profile).returns(mock)
  106 + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
  107 + product = fast_create(Product, :product_category_id => category.id)
  108 + assert_equal '', edit_product_ui_button(product, 'field', 'link to edit')
  109 + end
  110 +
  111 + should 'display ui_button_to_remote to edit product when user has permission' do
  112 + user = mock
  113 + user.expects(:has_permission?).with(anything, anything).returns(true)
  114 + @controller = mock
  115 + @controller.expects(:user).returns(user).at_least_once
  116 + @controller.expects(:profile).returns(mock)
  117 + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
  118 + product = fast_create(Product, :product_category_id => category.id)
  119 +
  120 + expects(:ui_button_to_remote).with('link to edit', {:update => "product-info", :url => {:controller => 'manage_products', :action => 'edit', :id => product.id, :field => 'info'}, :complete => "$('edit-product-button-ui-info').hide()", :method => :get}, :id => 'edit-product-remote-button-ui-info').returns('LINK')
  121 +
  122 + assert_equal 'LINK', edit_product_ui_button_to_remote(product, 'info', 'link to edit')
  123 + end
  124 +
  125 +
  126 + should 'display ui_button to edit product when user has permission' do
  127 + user = mock
  128 + user.expects(:has_permission?).with(anything, anything).returns(true)
  129 + @controller = mock
  130 + @controller.expects(:user).returns(user).at_least_once
  131 + @controller.expects(:profile).returns(mock)
  132 + category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
  133 + product = fast_create(Product, :product_category_id => category.id)
  134 +
  135 + expects(:ui_button).with('link to edit', { :action => 'add_input', :id => product.id }, {:id => 'edit-product-button-ui-info'}).returns('LINK')
  136 +
  137 + assert_equal 'LINK', edit_product_ui_button('info', 'link to edit', {:action => 'add_input', :id => product.id})
96 138 end
97 139  
98 140 protected
... ...
test/unit/product_category_test.rb
... ... @@ -17,13 +17,6 @@ class ProductCategoryTest &lt; Test::Unit::TestCase
17 17 assert_equivalent [p1], c1.all_products
18 18 end
19 19  
20   - should 'have consumers' do
21   - c = ProductCategory.create!(:name => 'base_cat', :environment => Environment.default)
22   - person = create_user('test_user').person
23   - c.consumers << person
24   - assert_includes c.consumers, person
25   - end
26   -
27 20 should 'return top level product categories for environment when no parent product category specified' do
28 21 env1 = Environment.create!(:name => 'test env 1')
29 22 env2 = Environment.create!(:name => 'test env 2')
... ...
test/unit/product_test.rb
... ... @@ -241,7 +241,7 @@ class ProductTest &lt; Test::Unit::TestCase
241 241 should 'not save without category' do
242 242 product = Product.new(:name => 'A product without category')
243 243 product.valid?
244   - assert product.errors.invalid?(:product_category)
  244 + assert product.errors.invalid?(:product_category_id)
245 245 end
246 246  
247 247 should 'format values to float with 2 decimals' do
... ... @@ -263,4 +263,35 @@ class ProductTest &lt; Test::Unit::TestCase
263 263 product = Product.new
264 264 assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image
265 265 end
  266 +
  267 + should 'have inputs' do
  268 + product = Product.new
  269 + assert_respond_to product, :inputs
  270 + end
  271 +
  272 + should 'return empty array if has no input' do
  273 + product = Product.new
  274 + assert product.inputs.empty?
  275 + end
  276 +
  277 + should 'return product inputs' do
  278 + ent = fast_create(Enterprise)
  279 + product = fast_create(Product, :enterprise_id => ent.id)
  280 + input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id)
  281 +
  282 + assert_equal [input], product.inputs
  283 + end
  284 +
  285 + should 'destroy inputs when product is removed' do
  286 + ent = fast_create(Enterprise)
  287 + product = fast_create(Product, :enterprise_id => ent.id)
  288 + input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id)
  289 +
  290 + services_category = fast_create(ProductCategory, :name => 'Services')
  291 + input2 = fast_create(Input, :product_id => product.id, :product_category_id => services_category.id)
  292 +
  293 + assert_difference Input, :count, -2 do
  294 + product.destroy
  295 + end
  296 + end
266 297 end
... ...