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,7 +18,6 @@ class ManageProductsController < ApplicationController
18 18
19 def index 19 def index
20 @products = @profile.products 20 @products = @profile.products
21 - @consumptions = @profile.consumptions  
22 end 21 end
23 22
24 def show 23 def show
@@ -38,7 +37,7 @@ class ManageProductsController < ApplicationController @@ -38,7 +37,7 @@ class ManageProductsController < ApplicationController
38 end 37 end
39 38
40 def new 39 def new
41 - @product = @profile.products.build(params[:product]) 40 + @product = @profile.products.build(:product_category_id => params[:selected_category_id])
42 @category = @product.product_category 41 @category = @product.product_category
43 @categories = ProductCategory.top_level_for(environment) 42 @categories = ProductCategory.top_level_for(environment)
44 @level = 0 43 @level = 0
@@ -75,12 +74,25 @@ class ManageProductsController < ApplicationController @@ -75,12 +74,25 @@ class ManageProductsController < ApplicationController
75 @edit = true 74 @edit = true
76 @level = @category.level 75 @level = @category.level
77 if request.post? 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 render :partial => 'shared/redirect_via_javascript', 78 render :partial => 'shared/redirect_via_javascript',
81 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } 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 render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } 96 render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' }
85 end 97 end
86 end 98 end
app/helpers/manage_products_helper.rb
@@ -89,8 +89,8 @@ module ManageProductsHelper @@ -89,8 +89,8 @@ module ManageProductsHelper
89 ) 89 )
90 end 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 content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') + 94 content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
95 content_tag('div', categories_selection_html, :id => 'categories_container_wrapper') 95 content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
96 end 96 end
@@ -108,7 +108,13 @@ module ManageProductsHelper @@ -108,7 +108,13 @@ module ManageProductsHelper
108 end 108 end
109 end 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 return '' unless (user && user.has_permission?('manage_products', profile)) 118 return '' unless (user && user.has_permission?('manage_products', profile))
113 options = html_options.merge(:id => 'link-edit-product-' + field) 119 options = html_options.merge(:id => 'link-edit-product-' + field)
114 120
@@ -124,12 +130,18 @@ module ManageProductsHelper @@ -124,12 +130,18 @@ module ManageProductsHelper
124 if html_options.has_key?(:class) 130 if html_options.has_key?(:class)
125 the_class << ' ' << html_options[:class] 131 the_class << ' ' << html_options[:class]
126 end 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 end 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 return '' unless (user && user.has_permission?('manage_products', profile)) 137 return '' unless (user && user.has_permission?('manage_products', profile))
132 options = html_options.merge(:id => 'edit-product-button-ui-' + field) 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 ui_button_to_remote(label, 146 ui_button_to_remote(label,
135 {:update => "product-#{field}", 147 {:update => "product-#{field}",
@@ -146,12 +158,6 @@ module ManageProductsHelper @@ -146,12 +158,6 @@ module ManageProductsHelper
146 end 158 end
147 end 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 def float_to_currency(value) 161 def float_to_currency(value)
156 number_to_currency(value, :unit => environment.currency_unit, :separator => environment.currency_separator, :delimiter => environment.currency_delimiter, :format => "%u %n") 162 number_to_currency(value, :unit => environment.currency_unit, :separator => environment.currency_separator, :delimiter => environment.currency_delimiter, :format => "%u %n")
157 end 163 end
app/models/consumption.rb
@@ -1,9 +0,0 @@ @@ -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 @@ @@ -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,9 +4,11 @@ class Product &lt; ActiveRecord::Base
4 has_many :product_categorizations 4 has_many :product_categorizations
5 has_many :product_qualifiers 5 has_many :product_qualifiers
6 has_many :qualifiers, :through => :product_qualifiers 6 has_many :qualifiers, :through => :product_qualifiers
  7 + has_many :inputs, :dependent => :destroy
7 8
8 validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true 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 validates_numericality_of :price, :allow_nil => true 13 validates_numericality_of :price, :allow_nil => true
12 validates_numericality_of :discount, :allow_nil => true 14 validates_numericality_of :discount, :allow_nil => true
app/models/product_category.rb
1 class ProductCategory < Category 1 class ProductCategory < Category
2 has_many :products 2 has_many :products
3 - has_many :consumptions  
4 - has_many :consumers, :through => :consumptions, :source => :profile 3 + has_many :inputs
5 4
6 def all_products 5 def all_products
7 Product.find(:all, :conditions => { :product_category_id => (all_children << self).map(&:id) }) 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,9 +120,6 @@ class Profile &lt; ActiveRecord::Base
120 120
121 acts_as_having_image 121 acts_as_having_image
122 122
123 - has_many :consumptions  
124 - has_many :consumed_product_categories, :through => :consumptions, :source => :product_category  
125 -  
126 has_many :tasks, :dependent => :destroy, :as => 'target' 123 has_many :tasks, :dependent => :destroy, :as => 'target'
127 124
128 has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name' 125 has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name'
app/views/manage_products/_categories_for_selection.rhtml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 <% javascript_tag do %> 3 <% javascript_tag do %>
4 jQuery('#categories_container_wrapper').scrollTo('100%', 1000) 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 $('hierarchy_navigation').update('<%= escape_javascript(hierarchy_category_navigation(@category, :make_links => true)) %>') 6 $('hierarchy_navigation').update('<%= escape_javascript(hierarchy_category_navigation(@category, :make_links => true)) %>')
7 toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, $('save_and_continue')) 7 toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, $('save_and_continue'))
8 <% end %> 8 <% end %>
app/views/manage_products/_display_category.rhtml
1 <div id='display-product-category'> 1 <div id='display-product-category'>
2 <p><%= hierarchy_category_navigation(@product.product_category, :make_links => false)%></p> 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 </div> 4 </div>
app/views/manage_products/_display_image.rhtml
@@ -2,4 +2,4 @@ @@ -2,4 +2,4 @@
2 <%= image_tag (@product.reload.image ? @product.image.public_filename : @product.default_image('thumb')), :class => 'product-pic' %> 2 <%= image_tag (@product.reload.image ? @product.image.public_filename : @product.default_image('thumb')), :class => 'product-pic' %>
3 </div> 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,6 +9,6 @@
9 <% if @product.has_basic_info? %> 9 <% if @product.has_basic_info? %>
10 <%= edit_product_button(@product, 'info', _('Edit basic information')) %> 10 <%= edit_product_button(@product, 'info', _('Edit basic information')) %>
11 <% else %> 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 <% end%> 14 <% end%>
app/views/manage_products/_display_inputs.rhtml 0 → 100644
@@ -0,0 +1,2 @@ @@ -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 <div id='display-product-name'> 1 <div id='display-product-name'>
2 <h2><%= @product.reload.name %></h2> 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 </div> 4 </div>
5 5
app/views/manage_products/add_input.rhtml 0 → 100644
@@ -0,0 +1,33 @@ @@ -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 <div class=product-category-hierarchy> 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 </div> 3 </div>
4 4
5 <div id="category-product-edition"> 5 <div id="category-product-edition">
@@ -8,16 +8,15 @@ @@ -8,16 +8,15 @@
8 8
9 <div id='request_result_message' style='display: none'></div> 9 <div id='request_result_message' style='display: none'></div>
10 10
11 - <% remote_form_for(:product, @product, 11 + <% remote_form_for(@product,
12 :loading => "open_loading('#{ _('loading...') }')", 12 :loading => "open_loading('#{ _('loading...') }')",
13 - :loaded => "close_loading()",  
14 :update => "request_result_message", 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 <h3><%= _('Edit category of this product:') %></h3> 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 <div id='categories_selection_actionbar'> 21 <div id='categories_selection_actionbar'>
23 <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %> 22 <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
app/views/manage_products/new.rhtml
@@ -6,11 +6,11 @@ @@ -6,11 +6,11 @@
6 :loading => "open_loading('#{ _('loading...') }')", 6 :loading => "open_loading('#{ _('loading...') }')",
7 :update => "request_result_message", 7 :update => "request_result_message",
8 :url => {:action => 'new'}, 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 <h3><%= _('Select the category of the new product or service') %></h3> 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 <div id='categories_selection_actionbar'> 15 <div id='categories_selection_actionbar'>
16 <%= button :back, _('Back to the product listing'), :action => 'index' %> 16 <%= button :back, _('Back to the product listing'), :action => 'index' %>
app/views/manage_products/show.rhtml
@@ -17,6 +17,10 @@ @@ -17,6 +17,10 @@
17 <%= render :partial => 'manage_products/display_info', :locals => {:product => @product} %> 17 <%= render :partial => 'manage_products/display_info', :locals => {:product => @product} %>
18 </div> 18 </div>
19 19
  20 + <div id='product-inputs'>
  21 + <%= render :partial => 'manage_products/display_inputs', :locals => {:product => @product} %>
  22 + </div>
  23 +
20 </div> 24 </div>
21 </div> 25 </div>
22 26
db/migrate/20100719142230_create_inputs.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -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 @@ @@ -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
@@ -160,12 +160,6 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do @@ -160,12 +160,6 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do
160 t.datetime "created_at" 160 t.datetime "created_at"
161 end 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 create_table "domains", :force => true do |t| 163 create_table "domains", :force => true do |t|
170 t.string "name" 164 t.string "name"
171 t.string "owner_type" 165 t.string "owner_type"
@@ -228,6 +222,13 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do @@ -228,6 +222,13 @@ ActiveRecord::Schema.define(:version =&gt; 20100722020357) do
228 t.integer "height" 222 t.integer "height"
229 end 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 create_table "product_categorizations", :force => true do |t| 232 create_table "product_categorizations", :force => true do |t|
232 t.integer "category_id" 233 t.integer "category_id"
233 t.integer "product_id" 234 t.integer "product_id"
features/manage_products.feature
@@ -351,3 +351,37 @@ Feature: manage products @@ -351,3 +351,37 @@ Feature: manage products
351 When I follow "Cancel" 351 When I follow "Cancel"
352 Then I should see "A new red bicycle" 352 Then I should see "A new red bicycle"
353 And I should be on Rede Moinho's page of product Bike 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,7 +2613,7 @@ div#activation_enterprise div {
2613 list-style: none; 2613 list-style: none;
2614 } 2614 }
2615 2615
2616 -#edit-product-button-ui-info { 2616 +#edit-product-remote-button-ui-info {
2617 margin-top: 40px; 2617 margin-top: 40px;
2618 } 2618 }
2619 2619
@@ -2655,6 +2655,11 @@ div#activation_enterprise div { @@ -2655,6 +2655,11 @@ div#activation_enterprise div {
2655 #product-qualifiers-list .product-certifier-title { 2655 #product-qualifiers-list .product-certifier-title {
2656 margin-right: 20px; 2656 margin-right: 20px;
2657 } 2657 }
  2658 +
  2659 +#edit-product-button-ui-inputs {
  2660 + margin-top: 20px;
  2661 +}
  2662 +
2658 /* ==> public/stylesheets/controller_cms.css <== */ 2663 /* ==> public/stylesheets/controller_cms.css <== */
2659 2664
2660 .controller-cms #article_types li { 2665 .controller-cms #article_types li {
@@ -3142,7 +3147,7 @@ h1#agenda-title { @@ -3142,7 +3147,7 @@ h1#agenda-title {
3142 3147
3143 /* ==> public/stylesheets/controller_manage_products.css <== */ 3148 /* ==> public/stylesheets/controller_manage_products.css <== */
3144 3149
3145 -#product_category_form { 3150 +#category_form {
3146 border: 1px solid #AABB88; 3151 border: 1px solid #AABB88;
3147 -moz-border-radius: 5px; 3152 -moz-border-radius: 5px;
3148 -webkit-border-radius: 5px; 3153 -webkit-border-radius: 5px;
test/factories.rb
@@ -330,4 +330,12 @@ module Noosfero::Factory @@ -330,4 +330,12 @@ module Noosfero::Factory
330 { :name => 'Product ' + factory_num_seq.to_s } 330 { :name => 'Product ' + factory_num_seq.to_s }
331 end 331 end
332 332
  333 + ###############################################
  334 + # Input
  335 + ###############################################
  336 +
  337 + def defaults_for_input
  338 + { }
  339 + end
  340 +
333 end 341 end
test/fixtures/consumptions.yml
@@ -1,5 +0,0 @@ @@ -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,7 +50,7 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
50 50
51 should "create new product" do 51 should "create new product" do
52 assert_difference Product, :count do 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 assert assigns(:product) 54 assert assigns(:product)
55 assert !assigns(:product).new_record? 55 assert !assigns(:product).new_record?
56 end 56 end
@@ -117,17 +117,16 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase @@ -117,17 +117,16 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
117 end 117 end
118 118
119 should "not edit to invalid parameters" do 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 assert_response :success 122 assert_response :success
123 - assert assigns(:product)  
124 - assert ! assigns(:product).valid? 123 + assert_template 'shared/_dialog_error_messages'
125 end 124 end
126 125
127 should "destroy product" do 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 assert_difference Product, :count, -1 do 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 assert_response :redirect 130 assert_response :redirect
132 assert_redirected_to :action => 'index' 131 assert_redirected_to :action => 'index'
133 assert assigns(:product) 132 assert assigns(:product)
@@ -136,10 +135,10 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase @@ -136,10 +135,10 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
136 end 135 end
137 136
138 should "fail to destroy product" do 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 Product.any_instance.stubs(:destroy).returns(false) 139 Product.any_instance.stubs(:destroy).returns(false)
141 assert_no_difference Product, :count do 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 assert_response :redirect 142 assert_response :redirect
144 assert_redirected_to :action => 'show' 143 assert_redirected_to :action => 'show'
145 assert assigns(:product) 144 assert assigns(:product)
@@ -159,20 +158,20 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase @@ -159,20 +158,20 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
159 category1 = fast_create(ProductCategory, :name => 'Category 1') 158 category1 = fast_create(ProductCategory, :name => 'Category 1')
160 category2 = fast_create(ProductCategory, :name => 'Category 2', :parent_id => category1) 159 category2 = fast_create(ProductCategory, :name => 'Category 2', :parent_id => category1)
161 assert_difference Product, :count do 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 assert_equal category2, assigns(:product).product_category 162 assert_equal category2, assigns(:product).product_category
164 end 163 end
165 end 164 end
166 165
167 should 'filter html from name of product' do 166 should 'filter html from name of product' do
168 category = fast_create(ProductCategory, :name => 'Category 1') 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 assert_sanitized assigns(:product).name 169 assert_sanitized assigns(:product).name
171 end 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 assert_equal "<b>descr bold</b>", assigns(:product).description 175 assert_equal "<b>descr bold</b>", assigns(:product).description
177 end 176 end
178 177
@@ -235,7 +234,7 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase @@ -235,7 +234,7 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
235 234
236 should 'render redirect_via_javascript template after save' do 235 should 'render redirect_via_javascript template after save' do
237 assert_difference Product, :count do 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 assert_template 'shared/_redirect_via_javascript' 238 assert_template 'shared/_redirect_via_javascript'
240 end 239 end
241 end 240 end
@@ -273,25 +272,37 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase @@ -273,25 +272,37 @@ class ManageProductsControllerTest &lt; Test::Unit::TestCase
273 end 272 end
274 273
275 should 'show product price when showing product if unit was informed' do 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 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/ 278 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/
  279 + assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
280 end 280 end
281 281
282 should 'show product price when showing product if discount was informed' do 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 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /List price:/ 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 assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /On sale:/ 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 end 290 end
289 291
290 should 'not show product price when showing product if unit not informed' do 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 end 306 end
296 307
297 end 308 end
test/unit/consumption_test.rb
@@ -1,14 +0,0 @@ @@ -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 @@ @@ -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,7 +55,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
55 @controller.expects(:profile).returns(mock) 55 @controller.expects(:profile).returns(mock)
56 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) 56 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
57 product = fast_create(Product, :product_category_id => category.id) 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 end 59 end
60 60
61 should 'display link to edit product when user has permission' do 61 should 'display link to edit product when user has permission' do
@@ -69,7 +69,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase @@ -69,7 +69,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
69 69
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') 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 end 73 end
74 74
75 should 'not display link to edit product category when user does not have permission' do 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,7 +80,7 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
80 @controller.expects(:profile).returns(mock) 80 @controller.expects(:profile).returns(mock)
81 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) 81 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
82 product = fast_create(Product, :product_category_id => category.id) 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 end 84 end
85 85
86 should 'display link to edit product category when user has permission' do 86 should 'display link to edit product category when user has permission' do
@@ -92,7 +92,49 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase @@ -92,7 +92,49 @@ class ManageProductsHelperTest &lt; Test::Unit::TestCase
92 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id) 92 category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
93 product = fast_create(Product, :product_category_id => category.id) 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 end 138 end
97 139
98 protected 140 protected
test/unit/product_category_test.rb
@@ -17,13 +17,6 @@ class ProductCategoryTest &lt; Test::Unit::TestCase @@ -17,13 +17,6 @@ class ProductCategoryTest &lt; Test::Unit::TestCase
17 assert_equivalent [p1], c1.all_products 17 assert_equivalent [p1], c1.all_products
18 end 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 should 'return top level product categories for environment when no parent product category specified' do 20 should 'return top level product categories for environment when no parent product category specified' do
28 env1 = Environment.create!(:name => 'test env 1') 21 env1 = Environment.create!(:name => 'test env 1')
29 env2 = Environment.create!(:name => 'test env 2') 22 env2 = Environment.create!(:name => 'test env 2')
test/unit/product_test.rb
@@ -241,7 +241,7 @@ class ProductTest &lt; Test::Unit::TestCase @@ -241,7 +241,7 @@ class ProductTest &lt; Test::Unit::TestCase
241 should 'not save without category' do 241 should 'not save without category' do
242 product = Product.new(:name => 'A product without category') 242 product = Product.new(:name => 'A product without category')
243 product.valid? 243 product.valid?
244 - assert product.errors.invalid?(:product_category) 244 + assert product.errors.invalid?(:product_category_id)
245 end 245 end
246 246
247 should 'format values to float with 2 decimals' do 247 should 'format values to float with 2 decimals' do
@@ -263,4 +263,35 @@ class ProductTest &lt; Test::Unit::TestCase @@ -263,4 +263,35 @@ class ProductTest &lt; Test::Unit::TestCase
263 product = Product.new 263 product = Product.new
264 assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image 264 assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image
265 end 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 end 297 end