- <%= labelled_select(_('Distance:'), 'radius', :first, :last, nil, [15, 30, 50, 100, 150, 200, 300, 400, 500, 1000].map{|n|[n, n.to_s + 'km']}) %>
-
-
-
- <%= link_to _('New category'), :action => 'new', :type => 'ProductCategory' %>
-
-
<%= render :partial => 'category', :collection => @regions %>
diff --git a/app/views/manage_products/_add_input.html.erb b/app/views/manage_products/_add_input.html.erb
deleted file mode 100644
index 9cd87d4..0000000
--- a/app/views/manage_products/_add_input.html.erb
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-<%= form_for(:input,
- :url => {:action => 'add_input', :id => @product},
- :html => {:method => 'post', :id => 'input-category-form'}
- ) do |f| %>
-
- <%= _('Choose an input or raw material to this product:') %>
-
- <%= categories_container(select_for_new_category(@categories, @level)) %>
-
-
-
- <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
-
- <%= ui_icon('ui-icon-alert') %>
- <%= _('This category does not allow registration of products, select a more specific category') %>
-
-
- <%= button :cancel, _('Cancel'), '#', :class => 'cancel-add-input' %>
-
-
-<% end %>
-
-<%= javascript_tag "add_input_stuff()" %>
diff --git a/app/views/manage_products/_categories_autocomplete.html.erb b/app/views/manage_products/_categories_autocomplete.html.erb
deleted file mode 100644
index 38a55dd..0000000
--- a/app/views/manage_products/_categories_autocomplete.html.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-<%= text_field_tag 'product_category_id', '', :placeholder => _('type a category for the product') %>
-
-<%= javascript_include_tag '/javascripts/product_categories.js' %>
-<%= javascript_tag do %>
- product_categories.autocomplete.search_url = <%= url_for(:controller => :manage_products, :action => :search_categories).to_json %>
- product_categories.autocomplete.select_url = <%= url_for(:controller => :manage_products, :action => :show_category_tree).to_json %>
- product_categories.autocomplete.load('#product_category_id')
-<% end %>
diff --git a/app/views/manage_products/_categories_for_selection.html.erb b/app/views/manage_products/_categories_for_selection.html.erb
deleted file mode 100644
index 9d18d09..0000000
--- a/app/views/manage_products/_categories_for_selection.html.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<%= select_for_categories(categories, level) %>
-
-<%= javascript_tag do %>
- jQuery(document).ready(function() {
- jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
- jQuery('#selected_category_id').val(<%= @category.id rescue nil %>)
- jQuery('#hierarchy_navigation').html(<%= hierarchy_category_navigation(@category, :make_links => true).to_json %>)
- toggleDisabled(<%= (!!(@category && @category.accept_products?)).to_json %>, jQuery('#save_and_continue'))
- });
-<% end %>
diff --git a/app/views/manage_products/_certifiers_for_selection.html.erb b/app/views/manage_products/_certifiers_for_selection.html.erb
deleted file mode 100644
index 99eecea..0000000
--- a/app/views/manage_products/_certifiers_for_selection.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-<%= select_certifiers(@qualifier) + remove_qualifier_button %>
-<%= javascript_tag do %>
- jQuery('#product-qualifiers-list *').removeClass('small-loading')
-<% end %>
diff --git a/app/views/manage_products/_display_category.html.erb b/app/views/manage_products/_display_category.html.erb
deleted file mode 100644
index 3662191..0000000
--- a/app/views/manage_products/_display_category.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- <%= edit_link( _('Change category'), { :action => 'edit_category', :id => @product.id}, :id => 'link-edit-product-category') %>
-
diff --git a/app/views/manage_products/_display_description.html.erb b/app/views/manage_products/_display_description.html.erb
deleted file mode 100644
index 45d6f7a..0000000
--- a/app/views/manage_products/_display_description.html.erb
+++ /dev/null
@@ -1,15 +0,0 @@
-<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
-<% if !@product.description.blank? %>
- <%= @product.description %>
- <%= edit_product_button_to_remote(@product, 'description', _('Edit description'), :title => _('Edit the description of your product and give consumers more information about what you are advertising')) %>
-<% else %>
- <%= edit_product_ui_button_to_remote(
- @product,
- 'description',
- _('Add some description to your product'),
- 'data-primary-icon' => 'ui-icon-pencil',
- 'data-secondary-icon' => 'ui-icon-triangle-1-s',
- :title => _('Add a description to your product and give consumers more information about what you are advertising')
- ) %>
- <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-description')") %>
-<% end%>
diff --git a/app/views/manage_products/_display_image.html.erb b/app/views/manage_products/_display_image.html.erb
deleted file mode 100644
index e8e44fb..0000000
--- a/app/views/manage_products/_display_image.html.erb
+++ /dev/null
@@ -1,11 +0,0 @@
-
- <%= image_tag (@product.reload.default_image('big')), :class => 'product-pic' %>
-
-
-<% if @product.image %>
- <%= link_to content_tag(:span, _('Zoom in')), @product.image.public_filename,
- :class => 'zoomify-image' %>
-<% end %>
-<%= add_zoom_to_images %>
-
-<%= edit_product_link_to_remote(@product, 'image', _('Change image')) %>
diff --git a/app/views/manage_products/_display_info.html.erb b/app/views/manage_products/_display_info.html.erb
deleted file mode 100644
index d7adc96..0000000
--- a/app/views/manage_products/_display_info.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
- <%= display_value(@product) %>
- <%= display_availability(@product) %>
- <%= display_qualifiers(@product) %>
-
- <% if @product.has_basic_info? %>
- <%= edit_product_button_to_remote(@product, 'info', _('Edit basic information'), :title => _('Click here to edit price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers')) %>
- <% else %>
- <%= edit_product_ui_button_to_remote(@product, 'info', _('Add price and other basic information'),
- :title => _('Click here to add 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')
- %>
- <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-info')") %>
- <% end%>
-
-
diff --git a/app/views/manage_products/_display_input.html.erb b/app/views/manage_products/_display_input.html.erb
deleted file mode 100644
index a54940b..0000000
--- a/app/views/manage_products/_display_input.html.erb
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
- <% if user && user.has_permission?('manage_products', profile) %>
- <%= javascript_tag "input_javascript_stuff(#{input.id})" %>
- <% end %>
diff --git a/app/views/manage_products/_display_inputs.html.erb b/app/views/manage_products/_display_inputs.html.erb
deleted file mode 100644
index 18307b5..0000000
--- a/app/views/manage_products/_display_inputs.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- <% if @product.inputs.empty? %>
- <%= edit_ui_button(
- _('Add the inputs or raw material used by this product'),
- {:action => 'add_input', :id => @product.id},
- :id => 'add-input-button',
- 'data-primary-icon' => 'ui-icon-pencil',
- 'data-secondary-icon' => 'ui-icon-triangle-1-s',
- :title => _('Add inputs or raw materials used by this product and give more transparency to consumers about your enterprise')
- ) %>
- <%= javascript_tag("render_jquery_ui_buttons('add-input-button')") %>
- <% else %>
- <%= edit_button(:add, _('Add new input or raw material'), {:action => 'add_input', :id => @product.id}, :id => 'add-input-button', :title => _('Add new input or raw material used by this product and give more transparency to consumers about your enterprise')) %>
- <%= content_tag('span', _('Drag the input with the mouse to change the order'), :class => 'hint', :style => 'display: none') %>
- <% end %>
-
-
-
-
-
-<% if user && user.has_permission?('manage_products', profile) %>
- <% if @product.inputs.size > 1 %>
- <%= javascript_tag "input_javascript_ordering_stuff()" %>
- <% end %>
- <%= javascript_tag "display_input_stuff()" %>
-<% end %>
diff --git a/app/views/manage_products/_display_name.html.erb b/app/views/manage_products/_display_name.html.erb
deleted file mode 100644
index 7d61afc..0000000
--- a/app/views/manage_products/_display_name.html.erb
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
<%= @product.name_with_unit %>
- <%= edit_product_link_to_remote(@product, 'name', _('Edit name and unit'), :title => _('Click here to edit the name of your product and the unit')) %>
-
-<%= javascript_tag do %>
- jQuery('#display-product-category .hierarchy-category').first().html('<%=
- escape_javascript(hierarchy_category_navigation(
- @product.product_category,
- :make_links => false,
- :hide_current_category => @product.name_is_blank?)
- )
- %>')
-<% end %>
diff --git a/app/views/manage_products/_display_price_details.html.erb b/app/views/manage_products/_display_price_details.html.erb
deleted file mode 100644
index 47f81c6..0000000
--- a/app/views/manage_products/_display_price_details.html.erb
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- <%= _('Inputs:') %>
-
- <%= float_to_currency(@product.inputs_cost) %>
-
-
- <% @product.price_details.each do |price_detail| %>
-
- <%= "%s:" % price_detail.name %>
- <%= float_to_currency(price_detail.price) %>
-
- <% end %>
-
-
diff --git a/app/views/manage_products/_edit_description.html.erb b/app/views/manage_products/_edit_description.html.erb
deleted file mode 100644
index 033d34d..0000000
--- a/app/views/manage_products/_edit_description.html.erb
+++ /dev/null
@@ -1,14 +0,0 @@
-<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
-<%= remote_form_for(@product,
- :loading => "small_loading('product-description-form')",
- :update => 'product-description',
- :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'},
- :html => {:id => 'product-description-form', :method => 'post'}) do |f| %>
-
- <%= labelled_form_field(_('Description:'), f.text_area(:description, :rows => 15, :style => 'width: 90%;', :class => 'mceEditor')) %>
- <% button_bar do %>
- <%= submit_button :save, _('Save') %>
- <%= cancel_edit_product_link(@product, 'description') %>
- <% end %>
-
-<% end %>
diff --git a/app/views/manage_products/_edit_image.html.erb b/app/views/manage_products/_edit_image.html.erb
deleted file mode 100644
index 55f8097..0000000
--- a/app/views/manage_products/_edit_image.html.erb
+++ /dev/null
@@ -1,26 +0,0 @@
-
- <%= image_tag (@product.reload.default_image('thumb')), :class => 'product-pic' %>
-
-
-<%= form_for(:product, :url => { :controller => 'manage_products', :action => 'edit', :id => @product, :field => 'image' }, :html => { :method => 'post', :id => 'uploadForm', :multipart => true}) do |f| %>
- <%= f.fields_for :image_builder, @product.image do |i| %>
- <%= i.file_field( :uploaded_data, { :size => 10 } ) %>
- <%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
- <% end %>
-
- <%= submit_button 'save', _('Save') %>
- <%= cancel_edit_product_link(@product, 'image') %>
-<% end %>
-
-
-
-<% if errors %>
- <%= render_dialog_error_messages 'product' %>
-<% end %>
diff --git a/app/views/manage_products/_edit_info.html.erb b/app/views/manage_products/_edit_info.html.erb
deleted file mode 100644
index 997a35f..0000000
--- a/app/views/manage_products/_edit_info.html.erb
+++ /dev/null
@@ -1,63 +0,0 @@
-<% if errors %>
- <%= render_dialog_error_messages 'product' %>
-<% end %>
-
-<%= remote_form_for(@product,
- :loading => "small_loading('product-info-form')",
- :update => 'product-info',
- :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'info'},
- :html => {:id => 'product-info-form', :method => 'post'}) do |f| %>
-
-
-
- <%= f.label :price, _('Price (%s)') % environment.currency_unit, :class => 'formlabel' %>
- <%= f.text_field(:price, :value => @product.formatted_value(:price), :class => 'numbers-only') %>
-
-
- <%= f.label :discount, _('Discount (%s)') % environment.currency_unit, :class => 'formlabel' %>
- <%= f.text_field(:discount, :value => @product.formatted_value(:discount), :class => 'numbers-only', :title => _('If your product is on sale, fill this field with the discount value')) %>
-
-
- <%= _('Available') %>
- <%= labelled_radio_button( _('Yes'), 'product[available]', true, @product.available, :id => 'product_available') + labelled_radio_button( _('No'), 'product[available]', false, !@product.available) %>
-
-
- <%= f.label :highlighted, _('Highlight this product?'), :class => 'formlabel' %>
- <%= f.check_box(:highlighted) %>
-
-
-
- <% if !environment.qualifiers.empty? %>
-
-
- <%= _('Qualifier') %>
- <%= _('Certifier') %>
-
- <% @product.qualifiers.each_with_index do |qualifier, index| %>
-
-
- <%= select_qualifiers(@product, qualifier.id) %>
-
-
- <%= select_certifiers(qualifier, @product) + remove_qualifier_button %>
-
-
- <% end %>
-
- <%= button_to_function(
- :add,
- _('Add new qualifier'),
- "new_qualifier_row('#product-qualifiers-list', '#{escape_javascript(CGI::escape_html(select_qualifiers(@product)))}', '#{escape_javascript(CGI::escape_html(remove_qualifier_button))}')"
- ) %>
- <%= hidden_field_tag "product[qualifiers_list][nil]" %>
- <% end %>
-
- <%= hidden_field_tag 'info-bar-update-url', @product.price_composition_bar_display_url, :class => 'bar-update-url' %>
-
- <% button_bar do %>
- <%= submit_button :save, _('Save') %>
- <%= cancel_edit_product_link(@product, 'info') %>
- <% end %>
-<% end %>
-
-<%= render :partial => 'shared/numbers_only_javascript' %>
diff --git a/app/views/manage_products/_edit_input.html.erb b/app/views/manage_products/_edit_input.html.erb
deleted file mode 100644
index 61d1425..0000000
--- a/app/views/manage_products/_edit_input.html.erb
+++ /dev/null
@@ -1,43 +0,0 @@
-<%= form_for(:input, :url => {:controller => 'manage_products', :action => 'edit_input', :id => @input},
- :html => {:method => 'post', :id => "edit-input-#{ @input.id }-form"}) do |f| %>
-
- <%= hidden_field_tag 'input-bar-update-url', @input.product.price_composition_bar_display_url, :class => 'bar-update-url' %>
- <%= hidden_field_tag 'inputs-cost-update-url', @input.product.inputs_cost_update_url %>
-
-
-
- <%= f.label :amount_used, label_amount_used(@input), :class => 'formlabel' %>
- <%= f.text_field(:amount_used, :value => @input.formatted_amount, :class => 'numbers-only amount-used') + select_unit(@input) %>
-
-
- <%= f.label :price_per_unit, _('Price %s (%s)') % [display_price_by(@input.unit), environment.currency_unit], :class => 'formlabel' %>
- <%= f.text_field(:price_per_unit, :value => @input.formatted_value(:price_per_unit), :class => 'numbers-only price-per-unit') %>
-
-
- <%= _("This input or raw material inpact on the final price of the product?") %>
-
- <%= radio_button :input, 'relevant_to_price', true %>
- <%= _('Yes') %>
- <%= radio_button :input, 'relevant_to_price', false %>
- <%= _('No') %>
-
-
-
- <%= _('Is it from solidarity economy?') %>
-
- <%= radio_button :input, 'is_from_solidarity_economy', true %>
- <%= _('Yes') %>
- <%= radio_button :input, 'is_from_solidarity_economy', false %>
- <%= _('No') %>
-
-
-
-
- <%= submit_button :save, _('Save'), :title => _('Save changes of this input or raw material') %>
- <%= button :cancel, _('Cancel'), '#', :class => 'cancel-edit-input', :id => "cancel-edit-input-#{@input.id}", :title => _('Cancel changes of this input or raw material') %>
-
-
-
-<% end %>
-
-<%= javascript_tag "edit_input_stuff(#{@input.id}, '#{environment.currency_separator}')" %>
diff --git a/app/views/manage_products/_edit_name.html.erb b/app/views/manage_products/_edit_name.html.erb
deleted file mode 100644
index 1e1e9e6..0000000
--- a/app/views/manage_products/_edit_name.html.erb
+++ /dev/null
@@ -1,21 +0,0 @@
-<%= remote_form_for(@product,
- :loading => "small_loading('product-name-form')",
- :update => 'product-name',
- :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'name'},
- :html => {:method => 'post', :id => 'product-name-form'}) do |f| %>
- <%= f.text_field(:name, :value => @product.name, :class => 'name_edition') %>
- <%= select_unit(@product) %>
-
- <% button_bar do %>
- <%= submit_button :save, _('Save') %>
- <%= cancel_edit_product_link(@product, 'name') %>
- <% end %>
-<% end %>
-
-
-
-<% if errors %>
- <%= render_dialog_error_messages 'product' %>
-<% end %>
diff --git a/app/views/manage_products/_edit_price_details.html.erb b/app/views/manage_products/_edit_price_details.html.erb
deleted file mode 100644
index 16480d8..0000000
--- a/app/views/manage_products/_edit_price_details.html.erb
+++ /dev/null
@@ -1,14 +0,0 @@
-<% price_details.each do |price_detail| %>
-
- <%= select_production_cost(@product, price_detail.production_cost_id) %>
- <%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', price_detail.formatted_value(:price), :class => 'numbers-only price-details-price', :size => 6)) %>
-
- <%= link_to_remote(_('Remove'),
- :update => "price-detail-#{price_detail.id}",
- :complete => "calculateValuesForBar();",
- data: {confirm: _('Are you sure that you want to remove this cost?')},
- :url => { :action => 'remove_price_detail', :id => price_detail, :product => @product }) %>
-
-<% end %>
-
-<%= render :partial => 'shared/numbers_only_javascript' %>
diff --git a/app/views/manage_products/_form.html.erb b/app/views/manage_products/_form.html.erb
deleted file mode 100644
index 8639138..0000000
--- a/app/views/manage_products/_form.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-<%= error_messages_for :product %>
-
-<%= form_for :product, :html => {:multipart => true }, :url => {:action => mode} do |f| %>
- <%= required_fields_message %>
-
- <%= display_form_field( _('Name:'), f.text_field(:name) ) %>
- <%= display_form_field( _('Price:'), f.text_field(:price) ) %>
- <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10, :class => 'mceEditor') ) %>
- <%= labelled_form_field(f.check_box(:highlighted) + _('Highlight this product'),'') %>
- <%= f.fields_for :image_builder, @product.image do |i| %>
- <%= file_field_or_thumbnail(_('Image:'), @product.image, i) %>
- <% end %>
-
- <% button_bar do %>
- <%= submit_button('save', (mode == 'new' ? _('Create product') : _('Save changes')), :cancel => {:action => 'index'} ) %>
- <% end %>
-<% end %>
diff --git a/app/views/manage_products/_input.html.erb b/app/views/manage_products/_input.html.erb
deleted file mode 100644
index 2ad8e32..0000000
--- a/app/views/manage_products/_input.html.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-
-<%= render :partial => 'manage_products/display_input', :locals =>{:input => input} %>
-
diff --git a/app/views/manage_products/_manage_product_details.html.erb b/app/views/manage_products/_manage_product_details.html.erb
deleted file mode 100644
index c7c84ce..0000000
--- a/app/views/manage_products/_manage_product_details.html.erb
+++ /dev/null
@@ -1,43 +0,0 @@
-
- <%= render :partial => 'manage_products/price_composition_bar' %>
-
-
-<%= form_tag({:action => 'manage_product_details'}, :method => 'post', :id => 'manage-product-details-form') do %>
-
-
-
- <%= _('Inputs') %>
-
- <%= float_to_currency(@product.inputs_cost) %>
-
-
- <%= _('This value is composed by the total value of registered inputs') %>
-
-
- <%= render :partial => 'manage_products/edit_price_details', :locals => {:price_details => @product.price_details} %>
-
-
-
- <%= hidden_field(:product, :inputs_cost) %>
- <%= hidden_field(:product, :price) %>
-
- <% button_bar do %>
- <%= submit_button :save, _('Save'), :disabled => '', :class => 'disabled' %>
- <%= button :cancel, _('Cancel'), '#', class: 'cancel-price-details', data: {confirm: _('If you leave, you will lose all unsaved information. Are you sure you want to quit?')} %>
- <%= button(:add, _('New cost'), '#', :id => 'add-new-cost') %>
-
- <% end %>
-
-<% end %>
-
-
-
-
- <%= select_production_cost(@product) %>
- <%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', nil, :class => 'numbers-only price-details-price', :size => 6)) %>
- <%= link_to(_('Cancel'), '#', {:class => 'cancel-new-cost'}) %>
-
-
-
-
-<%= render :partial => 'shared/numbers_only_javascript' %>
diff --git a/app/views/manage_products/_price_composition_bar.html.erb b/app/views/manage_products/_price_composition_bar.html.erb
deleted file mode 100644
index 7ec3d97..0000000
--- a/app/views/manage_products/_price_composition_bar.html.erb
+++ /dev/null
@@ -1,22 +0,0 @@
-<%= javascript_tag do %>
- var value = <%= @product.price_description_percentage %>;
- var total_cost = <%= @product.total_production_cost %>;
- var price = '<%= @product.formatted_value(:price) %>';
- var described = false;
- var currency_format = { separator : '<%= environment.currency_separator %>', delimiter : '<%= environment.currency_delimiter %>', unit : '<%= environment.currency_unit %>' };
- if (<%= @product.price_described? %>) {
- var described = true;
- }
- priceCompositionBar(value,described,total_cost,price);
-<% end %>
-
-
-
-
-
- <%= price_composition_progressbar_text(@product) %>
-
-
-
' data-price-described-notice='<%= _("Congratulations! Now the price is open to the public") %>'>
-
-
diff --git a/app/views/manage_products/_price_details_button.html.erb b/app/views/manage_products/_price_details_button.html.erb
deleted file mode 100644
index 8ee8eaf..0000000
--- a/app/views/manage_products/_price_details_button.html.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<%= edit_ui_button(
- _('Describe here the cost of production'),
- {:action => 'manage_product_details', :id => @product.id},
- :id => 'manage-product-details-button',
- 'data-primary-icon' => 'ui-icon-pencil',
- 'data-secondary-icon' => 'ui-icon-triangle-1-s',
- :title => _('Describe details about how the price was defined')
-) %>
-<%= javascript_tag("render_jquery_ui_buttons('manage-product-details-button')") %>
-
diff --git a/app/views/manage_products/_selected_category_tree.html.erb b/app/views/manage_products/_selected_category_tree.html.erb
deleted file mode 100644
index 120d6b5..0000000
--- a/app/views/manage_products/_selected_category_tree.html.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-<%= categories_container selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true) %>
-
diff --git a/app/views/manage_products/edit.html.erb b/app/views/manage_products/edit.html.erb
deleted file mode 100644
index af940d0..0000000
--- a/app/views/manage_products/edit.html.erb
+++ /dev/null
@@ -1,3 +0,0 @@
- <%= _('Editing') %> <%= @product.name %>
-
-<%= render :partial => 'manage_products/form', :locals => {:mode => 'edit'} %>
diff --git a/app/views/manage_products/edit_category.html.erb b/app/views/manage_products/edit_category.html.erb
deleted file mode 100644
index 7980257..0000000
--- a/app/views/manage_products/edit_category.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-
- <%= hierarchy_category_navigation(@category, :make_links => false)%>
-
-
-
-
-
<%= @product.name %>
-
-
-
- <%= remote_form_for(@product,
- :loading => "open_loading('#{ _('loading...') }')",
- :update => "request_result_message",
- :url => {:action => 'edit_category', :id => @product},
- :html => {:method => 'post', :id => 'category_form'}) do |f| %>
-
-
<%= _('Edit category of this product:') %>
-
- <%= render 'manage_products/selected_category_tree' %>
-
-
- <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
-
- <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
-
- <%= ui_icon('ui-icon-alert') %>
- <%= _('This category does not allow registration of products, select a more specific category') %>
-
-
-
-
- <% end %>
-
diff --git a/app/views/manage_products/index.html.erb b/app/views/manage_products/index.html.erb
deleted file mode 100644
index f4c5ae4..0000000
--- a/app/views/manage_products/index.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
- <%=_('Listing products and services') %>
-
-
-
- <%= _('Product') %>
- <%= _('Price') %>
- <%= _('Actions') %>
-
- <% if @products.empty? %>
-
- <%= _('(no product registered yet)') %>
-
- <% end %>
- <% @products.each do |product| %>
-
- <%= link_to product.name, :action => 'show', :id => product %>
- <%= product.price %>
-
- <%= button :delete, _('Remove'), {action: 'destroy', id: product}, data: {confirm: _('Are you sure you want to remove this product?')} %>
-
-
- <% end %>
-
-
-<%= pagination_links @products %>
-
-<% button_bar do %>
- <%= button :add, _('New product or service'), :action => 'new' if @profile.create_product? %>
- <%= button :back, _('Back'), { :controller => 'profile_editor', :profile => @profile.identifier, :action => 'index' } %>
-<% end %>
diff --git a/app/views/manage_products/new.html.erb b/app/views/manage_products/new.html.erb
deleted file mode 100644
index 867dda0..0000000
--- a/app/views/manage_products/new.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-<%= _('New product or service') %>
-
-
-
-<%= remote_form_for @product,
- :loading => "open_loading('#{ _('loading...') }')",
- :update => "request_result_message",
- :url => {:action => 'new'},
- :html => {:method => 'post', :id => 'category_form'} do |f| %>
-
- <%= _('Select the category of the new product or service') %>
-
- <%= categories_container(select_for_new_category(@categories, @level)) %>
-
-
- <%= button :back, _('Back to the product listing'), :action => 'index' %>
-
- <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
-
- <%= ui_icon('ui-icon-alert') %>
- <%= _('This category does not allow registration of products, select a more specific category') %>
-
-
-
-
-<% end %>
-
-<%= javascript_tag do %>
- toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, jQuery('#save_and_continue')[0])
-<% end %>
diff --git a/app/views/manage_products/show.html.erb b/app/views/manage_products/show.html.erb
deleted file mode 100644
index 5c7acd4..0000000
--- a/app/views/manage_products/show.html.erb
+++ /dev/null
@@ -1,74 +0,0 @@
-
- <%= render :partial => 'manage_products/display_category' %>
-
-
-
-
-
- <%= render :partial => 'manage_products/display_name' %>
-
-
-
-
- <%= render :partial => 'manage_products/display_image' %>
-
-
-
- <%= render :partial => 'manage_products/display_info' %>
-
-
-
-
-
- <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty? && !@product.price_described? ) %>
- <% plugins_tabs = plugins_product_tabs %>
-
-
-
-
-
- <%= render :partial => 'manage_products/display_description' %>
-
-
-
- <%= render :partial => 'manage_products/display_inputs' %>
-
-
- <% if @product.price_described? || @allowed_user %>
-
- <%= render :partial => 'manage_products/display_price_details' %>
- <%= render :partial => 'manage_products/price_details_button' %>
-
- <% end %>
-
- <% plugins_tabs.each do |tab| %>
-
<%= raw tab[:content] %>
- <% end %>
-
-
- <% end %>
-
-
-
-<% button_bar do %>
- <%= button :back, _('Back to the product listing'), :controller => 'catalog', :action => 'index' %>
- <%= button :delete, _('Remove product or service'), {:action => 'destroy', :id => @product}, :class => 'requires-permission-manage_products', :style => 'display:none;' %>
-<% end %>
diff --git a/app/views/map_balloon/profile.html.erb b/app/views/map_balloon/profile.html.erb
index 0dff4d4..9446f60 100644
--- a/app/views/map_balloon/profile.html.erb
+++ b/app/views/map_balloon/profile.html.erb
@@ -17,7 +17,7 @@
<%= _('Address: ') + @profile.address %>
<% end %>
<% if @profile.respond_to?(:products) and !@profile.products.blank? %>
- <%= _('Products/Services: ') + @profile.products.map{|i| link_to(i.name, :controller => 'manage_products', :profile => @profile.identifier, :action => 'show', :id => i.id)}.join(', ') %>
+ <%= _('Products/Services: ') + @profile.products.map{|i| link_to(i.name, controller: 'products_plugin/page', profile: @profile.identifier, action: 'show', id: i.id)}.join(', ') %>
<% end %>
<% if @profile.respond_to?(:distance) and !@profile.distance.nil? %>
<%= _('Distance: ') + "%.2f%" % @profile.distance %>
diff --git a/app/views/person_notifier/mailer/_create_product.html.erb b/app/views/person_notifier/mailer/_create_product.html.erb
deleted file mode 120000
index e1169fd..0000000
--- a/app/views/person_notifier/mailer/_create_product.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-../../profile/_create_product.html.erb
\ No newline at end of file
diff --git a/app/views/person_notifier/mailer/_remove_product.html.erb b/app/views/person_notifier/mailer/_remove_product.html.erb
deleted file mode 120000
index 49ea419..0000000
--- a/app/views/person_notifier/mailer/_remove_product.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-../../profile/_remove_product.html.erb
\ No newline at end of file
diff --git a/app/views/person_notifier/mailer/_update_product.html.erb b/app/views/person_notifier/mailer/_update_product.html.erb
deleted file mode 120000
index 81d9f5e..0000000
--- a/app/views/person_notifier/mailer/_update_product.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-../../profile/_update_product.html.erb
\ No newline at end of file
diff --git a/app/views/profile/_create_product.html.erb b/app/views/profile/_create_product.html.erb
deleted file mode 100644
index 094309f..0000000
--- a/app/views/profile/_create_product.html.erb
+++ /dev/null
@@ -1,13 +0,0 @@
-
- <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
-
-
-
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
-
<%= time_ago_in_words activity.created_at %>
-
-
- <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
-
-
-
-
diff --git a/app/views/profile/_remove_product.html.erb b/app/views/profile/_remove_product.html.erb
deleted file mode 100644
index 1fb0afa..0000000
--- a/app/views/profile/_remove_product.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
-
<%= time_ago_in_words activity.created_at %>
-
-
- <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
-
-
-
-
diff --git a/app/views/profile/_update_product.html.erb b/app/views/profile/_update_product.html.erb
deleted file mode 100644
index 094309f..0000000
--- a/app/views/profile/_update_product.html.erb
+++ /dev/null
@@ -1,13 +0,0 @@
-
- <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
-
-
-
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
-
<%= time_ago_in_words activity.created_at %>
-
-
- <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
-
-
-
-
diff --git a/app/views/profile_editor/_organization.html.erb b/app/views/profile_editor/_organization.html.erb
index 12df551..7d1f581 100644
--- a/app/views/profile_editor/_organization.html.erb
+++ b/app/views/profile_editor/_organization.html.erb
@@ -66,8 +66,3 @@
<%= labelled_check_box(_('Enable "contact us"'), 'profile_data[enable_contact_us]', "1", @profile.enable_contact_us) if @profile.enterprise? %>
<%= render :partial => 'moderation', :locals => { :profile => @profile } %>
-
-<% if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') %>
- <%=_('Products/Services catalog')%>
- <%= labelled_form_field(_('Number of products/services displayed per page on catalog'), text_field(:profile_data, :products_per_catalog_page, :size => 3)) %>
-<% end %>
diff --git a/app/views/profile_editor/index.html.erb b/app/views/profile_editor/index.html.erb
index 15326f4..9c99687 100644
--- a/app/views/profile_editor/index.html.erb
+++ b/app/views/profile_editor/index.html.erb
@@ -47,8 +47,6 @@
<%= control_panel_button(_('Manage Members'), 'members', :controller => 'profile_members') if profile.organization? && user.has_permission?(:manage_memberships, profile) %>
- <%= control_panel_button(_('Manage Products/Services'), 'products', :controller => 'manage_products') if profile.enterprise? && environment.enabled?('products_for_enterprises') %>
-
<% if !environment.enabled?('disable_asset_enterprises') %>
<% if profile.is_validation_entity? %>
<%= control_panel_button(_('Enterprise Validation'), 'validation', :controller => 'enterprise_validation') %>
diff --git a/app/views/search/_display_results.html.erb b/app/views/search/_display_results.html.erb
index 123fadc..469e38e 100644
--- a/app/views/search/_display_results.html.erb
+++ b/app/views/search/_display_results.html.erb
@@ -17,9 +17,10 @@
<% search[:results].each do |hit| %>
- <% partial = partial_for_class(hit.class, display) %>
- <% variable_name = partial.gsub("#{display}_", '').to_sym %>
- <%= render :partial => partial, :locals => {variable_name => hit} %>
+ <%= render_for_class hit.class do |klass| %>
+ <% name = klass.name.underscore %>
+ <%= render partial_name_for(name, display), name.split('/').last.to_sym => hit %>
+ <% end %>
<% end %>
diff --git a/app/views/search/_full_product.html.erb b/app/views/search/_full_product.html.erb
deleted file mode 100644
index e6ccd1b..0000000
--- a/app/views/search/_full_product.html.erb
+++ /dev/null
@@ -1,85 +0,0 @@
-<% extra_content = @plugins.dispatch(:asset_product_extras, product).collect { |content| instance_exec(&content) } %>
-<% extra_properties = @plugins.dispatch(:asset_product_properties, product) %>
-
-
-
-
- <%= render :partial => 'search/image', :object => product %>
-
- <% if product.available %>
- <% if product.price && product.price > 0 %>
- <% has_discount = product.discount && product.discount > 0 %>
- <% if product.price %>
-
<%=_("from") if has_discount %> <%= price_span(product.price, :class => "search-product-price " + (has_discount ? 'with-discount' : '')) %>
- <% if has_discount %>
-
<%=_("by")%> <%= price_span(product.price_with_discount, :class => "search-product-price") %>
- <% end %>
- <% if product.unit %>
-
<%= _('/') %> <%= product.unit.name %>
- <% end %>
- <% end %>
-
- <% end %>
- <% else %>
-
<%= _('Not available') %>
- <% end %>
-
-
-
- <%= link_to_product product, :class => 'search-result-title' %>
-
- <%= _('Supplier') %> <%= link_to_homepage product.enterprise.name, product.enterprise %>
-
-
- <% if product.description %>
- <% desc_stripped = strip_tags(product.description) %>
- <%= _('Description') %> <%= excerpt desc_stripped, desc_stripped.first(3), radius: 300 %>
- <% end %>
-
-
-
-
- <% if product.enterprise.region %>
- <%= _('City') %>
- <%= city_with_state(product.enterprise.region) %>
- <% end %>
-
-
- <% if product.product_qualifiers.count > 0 %>
- <%= _('Qualifiers') %>
- <% product.product_qualifiers.each do |pq| %>
- <% if pq.qualifier %>
- <%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %>
- <% end %>
- <% if pq.certifier %>
- <%= _('cert. ') + pq.certifier.name + _(";") %>
- <% end %>
- <% end %>
- <% end %>
-
-
-
-
-
- <%= safe_join(extra_content, '\n') %>
- <% extra_properties.each do |property| %>
- <%= ''.html_safe + property[:name] + ': ' + instance_exec(&property[:content]) %>
- <% end %>
-
-
diff --git a/app/views/search/_image.html.erb b/app/views/search/_image.html.erb
index 8e129fb..ca3adb4 100644
--- a/app/views/search/_image.html.erb
+++ b/app/views/search/_image.html.erb
@@ -36,17 +36,6 @@
<%= _('No image') %>
<% end %>
- <% elsif image.is_a? Product %>
- <% if image.image %>
-
- <%= link_to '', product_path(image), :class => "search-image-pic",
- :style => 'background-image: url(%s)'% image.default_image(:thumb) %>
- <%= link_to content_tag(:span, _('Zoom in')), image.image.public_filename,
- :class => 'zoomify-image' %>
-
- <% else %>
- <%= _('No image') %>
- <% end %>
<% else %>
<% end %>
diff --git a/app/views/search/products.html.erb b/app/views/search/products.html.erb
deleted file mode 120000
index 46521ac..0000000
--- a/app/views/search/products.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-search_page.html.erb
\ No newline at end of file
diff --git a/app/views/search/products.js.erb b/app/views/search/products.js.erb
deleted file mode 120000
index 4f709c8..0000000
--- a/app/views/search/products.js.erb
+++ /dev/null
@@ -1 +0,0 @@
-search.js.erb
\ No newline at end of file
diff --git a/config/initializers/action_tracker.rb b/config/initializers/action_tracker.rb
index 6e25292..7080775 100644
--- a/config/initializers/action_tracker.rb
+++ b/config/initializers/action_tracker.rb
@@ -32,15 +32,6 @@ ActionTrackerConfig.verbs = {
reply_scrap_on_self: {
},
- create_product: {
- },
-
- update_product: {
- },
-
- remove_product: {
- },
-
favorite_enterprise: {
},
diff --git a/config/routes.rb b/config/routes.rb
index b20fff6..21c706d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -56,6 +56,13 @@ Noosfero::Application.routes.draw do
# search
match 'search(/:action(/*category_path))', controller: 'search', via: :all
+ ##
+ # Keep products URL compatibility
+ get 'catalog/:profile', to: redirect{ |params, request| "/profile/#{request.params[:profile]}/plugin/products/catalog" }
+ get 'myprofile/:profile/manage_products(/:action(/:id))', to: (redirect do |params, request|
+ "/profile/#{request.params[:profile]}/plugin/products/page/#{request.params[:action]}/#{request.params[:id]}"
+ end)
+
# events
match 'profile/:profile/events_by_day', controller: 'events', action: 'events_by_day', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
match 'profile/:profile/events_by_month', controller: 'events', action: 'events_by_month', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
@@ -63,9 +70,6 @@ Noosfero::Application.routes.draw do
match 'profile/:profile/events/:year/:month', controller: 'events', action: 'events', year: /\d*/, month: /\d*/, profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
match 'profile/:profile/events', controller: 'events', action: 'events', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
- # catalog
- match 'catalog/:profile', controller: 'catalog', action: 'index', profile: /#{Noosfero.identifier_format_in_url}/i, as: :catalog, via: :all
-
# invite
match 'profile/:profile/invite/friends', controller: 'invite', action: 'invite_friends', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
match 'profile/:profile/invite/:action', controller: 'invite', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
@@ -95,6 +99,7 @@ Noosfero::Application.routes.draw do
# chat
match 'chat(/:action(/:id))', controller: 'chat', via: :all
+
######################################################
## Controllers that are profile-specific (for profile admins )
######################################################
diff --git a/db/migrate/20160422163123_enable_products_plugin_on_environments.rb b/db/migrate/20160422163123_enable_products_plugin_on_environments.rb
new file mode 100644
index 0000000..6ab12b4
--- /dev/null
+++ b/db/migrate/20160422163123_enable_products_plugin_on_environments.rb
@@ -0,0 +1,33 @@
+class Product < ApplicationRecord
+end
+class Profile < ApplicationRecord
+ has_many :products
+end
+class Environment < ApplicationRecord
+ has_many :profiles
+ has_many :products, through: :profiles
+
+ acts_as_having_settings field: :settings
+ settings_items :enabled_plugins, type: Array
+end
+
+class EnableProductsPluginOnEnvironments < ActiveRecord::Migration
+
+ def up
+ environments = Environment.all
+ products_used = environments.any?{ |e| e.products.count > 0 }
+ return unless products_used
+
+ Bundler.clean_system 'script/noosfero-plugins enable products'
+ environments.each do |e|
+ next unless e.products.count > 0
+ e.enabled_plugins << 'ProductsPlugin'
+ e.save!
+ end
+ end
+
+ def down
+ say "this migration can't be reverted"
+ end
+
+end
diff --git a/db/schema.rb b/db/schema.rb
index 586cf3e..d195765 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160408011720) do
+ActiveRecord::Schema.define(version: 20160422163123) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
diff --git a/features/browse_catalogs.feature b/features/browse_catalogs.feature
deleted file mode 100644
index e291cdd..0000000
--- a/features/browse_catalogs.feature
+++ /dev/null
@@ -1,317 +0,0 @@
-Feature: browse catalogs
- As a noosfero visitor
- I want to browse catalogs of products
-
- Background:
- Given the following users
- | login | name |
- | joaosilva | Joao Silva |
- And the following enterprises
- | identifier | owner | name | enabled |
- | artebonito | joaosilva | Associação de Artesanato de Bonito | true |
- And feature "products_for_enterprises" is enabled on environment
- And the following product_categories
- | name |
- | categ1 |
- | food |
- And I am on /catalog/artebonito
-
- Scenario: display titles
- Then the page title should be "Associação de Artesanato de Bonito"
- And I should see "Products/Services"
-
- Scenario: display the simplest possible product
- Given the following products
- | owner | category |
- | artebonito | categ1 |
- And I am on /catalog/artebonito
- Then I should see "categ1" within "li.product-link"
- And I should see "No image" within ".no-image"
- And I should not see "unit" within "#product-list"
- And I should not see "product unavailable"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: display a simple product without price
- Given the following products
- | owner | category | name |
- | artebonito | categ1 | Produto1 |
- And I am on /catalog/artebonito
- Then I should see "Produto1" within "li.product-link"
- And I should see "No image" within ".no-image"
- And I should not see "unit" within "#product-list"
- And I should not see "product unavailable"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: display a simple product without details
- Given the following products
- | owner | category | name | price |
- | artebonito | categ1 | Produto1 | 50.00 |
- And I am on /catalog/artebonito
- Then I should see "Produto1" within "li.product-link"
- And I should see "50.00" within "span.product-price"
- And I should see "unit" within "span.product-unit"
- And I should see "No image" within ".no-image"
- And I should not see "product unavailable"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: don't display the price when it's $0.00
- Given the following products
- | owner | category | name | price |
- | artebonito | categ1 | Produto1 | 0.00 |
- And I am on /catalog/artebonito
- Then I should see "Produto1" within "li.product-link"
- And I should not see "0.00"
-
- Scenario: don't display the price when it's not defined
- Given the following products
- | owner | category | name |
- | artebonito | categ1 | Produto1 |
- And I am on /catalog/artebonito
- Then I should see "Produto1" within "li.product-link"
- And I should not see "0.00"
- And I should see "No image" within ".no-image"
- And I should not see "product unavailable"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: product name links to product page
- Given the following products
- | owner | category | name | price |
- | artebonito | categ1 | Produto1 | 50.00 |
- And I am on /catalog/artebonito
- When I follow "Produto1" within "li.product-link"
- Then I should be taken to "Produto1" product page
-
- Scenario: display product with custom image
- Given the following products
- | owner | category | name | price | img |
- | artebonito | categ1 | Agrotox | 12.34 | agrotox |
- And I am on /catalog/artebonito
- Then I should see "Agrotox" within "li.product-link"
- And I should see "12.34" within "span.product-price"
- And I should see "unit" within "span.product-unit"
- And I should not see "No image"
- And I should not see "product unavailable"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: display "zoom in" button
- Given the following products
- | owner | category | name | price | img |
- | artebonito | categ1 | Agrotox | 12.34 | agrotox |
- And I am on /catalog/artebonito
- And I should not see "No image"
- And I should see "Zoom in" within ".zoomify-image"
-
- Scenario: image links to product page
- Given the following products
- | owner | category | name | price | img |
- | artebonito | categ1 | Agrotox | 12.34 | agrotox |
- And I am on /catalog/artebonito
- When I follow "Agrotox" within ".product-image-link"
- Then I should be taken to "Agrotox" product page
-
- Scenario: display product with discount
- Given the following products
- | owner | category | name | price | discount | img |
- | artebonito | categ1 | Semterrinha | 99.99 | 12.34 | semterrinha |
- And I am on /catalog/artebonito
- Then I should see "Semterrinha" within "li.product-link"
- And I should see "99.99" within "span.product-discount"
- And I should see "87.65" within "span.product-price"
- And I should not see "No image"
- And I should not see "description"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- @selenium-fixme
- Scenario: display description button when needed (but not the description)
- Given the following products
- | owner | category | name | price | description |
- | artebonito | categ1 | Produto2 | 12.34 | A small description for a product that doesn't exist. |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- Then I should see "Produto2" within "li.product-link"
- And I should see "12.34" within "span.product-price"
- And I should see "description" within "#product-description-button"
- And "description" should not be visible within "product-description-button"
- And I should see "A small description" within "#product-description"
- And "A small description for a product that doesn't exist" should not be visible within "product-description"
-
- @selenium-fixme
- Scenario: display description when button is clicked
- Given the following products
- | owner | category | name | price | description |
- | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- When I follow "product-description-button"
- Then I should see "A small description" within "#product-description"
- And "A small description for a product that doesn't exist" should not be visible within "product-description"
-
- @selenium-fixme
- Scenario: hide description
- Given the following products
- | owner | category | name | price | description |
- | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- When I click "product-description-button"
- Then I should see "A small description" within "#product-description"
- And the "product-description" should be visible
- When I click "product-list"
- Then the "product-description" should not be visible
-
- Scenario: display unavailable product
- Given the following products
- | owner | category | name | price | available |
- | artebonito | categ1 | Prod3 | 12.34 | false |
- And I am on /catalog/artebonito
- Then I should see "Prod3" within "li.not-available"
- And I should see "12.34" within "li.not-available"
- And I should see "product unavailable" within "li.product-unavailable"
- And I should not see "qualifiers"
- And I should not see "price composition"
-
- Scenario: display qualifiers
- Given the following qualifiers
- | name |
- | Organic |
- And the following certifiers
- | name | qualifiers |
- | Colivre | Organic |
- And the following products
- | owner | category | name | price | qualifier |
- | artebonito | categ1 | Banana | 0.99 | Organic |
- And I am on /catalog/artebonito
- Then I should see "Banana" within "li.product-link"
- And I should see "0.99" within "span.product-price"
- And I should see "qualifiers" within "li.product-qualifiers"
- And I should see "Organic" within "span.search-product-qualifier"
- And I should not see "price composition"
-
- @selenium-fixme
- Scenario: not display price composition button if price is not described
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Bananada | 10.00 |
- And the following input
- | product | category | price_per_unit | amount_used |
- | Bananada | food | 0.99 | 5 |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- Then I should see "Bananada" within "li.product-link"
- And I should see "10.00" within "span.product-price"
- And the "#product-price-composition-button" should not be visible
-
- @selenium-fixme
- Scenario: display price composition button (but not inputs)
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Bananada | 10.00 |
- And the following input
- | product | category | price_per_unit | amount_used |
- | Bananada | food | 2.00 | 5 |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- Then I should see "Bananada" within "li.product-link"
- And I should see "10.00" within "span.product-price"
- And I should see "price composition" within "#product-price-composition-button"
- And the "#product-price-composition-button" should be visible
- And I should see "food" within "#product-price-composition"
- And I should see "10.00" within "#product-price-composition"
-
- @selenium-fixme
- Scenario: display price composition when button is clicked
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Bananada | 10.88 |
- And the following input
- | product | category | price_per_unit | amount_used |
- | Bananada | food | 2.72 | 4 |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- When I click "#product-price-composition-button"
- Then the "#product-price-composition" should be visible
- And I should see "food" within "#product-price-composition"
- And I should see "10.88" within "#product-price-composition"
-
- @selenium-fixme
- Scenario: display inputs and raw materials button when not completely filled
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Vitamina | 17.99 |
- And the following unit
- | name | plural |
- | Liter | Liters |
- And the following input
- | product | category |
- | Vitamina | food |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- Then the "#inputs-button" should be visible
- And I should see "inputs and raw materials" within "#inputs-button"
-
- @selenium-fixme
- Scenario: display inputs and raw materials button
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Vitamina | 17.99 |
- And the following unit
- | name | plural |
- | Liter | Liters |
- And the following input
- | product | category | price_per_unit | amount_used | unit |
- | Vitamina | food | 1.45 | 7 | Liter |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- Then I should see "Vitamina" within "li.product-link"
- And I should see "17.99" within "span.product-price"
- And the "#inputs-button" should be visible
- And I should see "inputs and raw materials" within "#inputs-button"
- And the "#inputs-description" should not be visible
- And I should see "7.0 Liter of food" within "#inputs-description"
-
- @selenium-fixme
- Scenario: display inputs and raw materials description
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Vitamina | 17.99 |
- And the following unit
- | name | plural |
- | Liter | Liters |
- And the following input
- | product | category | price_per_unit | amount_used | unit |
- | Vitamina | food | 1.45 | 7 | Liter |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- When I click "#inputs-button"
- Then the "#inputs-description" should be visible
- And I should see "7.0 Liter of food" within "#inputs-description"
-
- @selenium-fixme
- Scenario: hide inputs and raw materials
- Given the following product
- | owner | category | name | price |
- | artebonito | food | Vitamina | 17.99 |
- And the following unit
- | name | plural |
- | Liter | Liters |
- And the following input
- | product | category | price_per_unit | amount_used | unit |
- | Vitamina | food | 1.45 | 7 | Liter |
- And I am on /catalog/artebonito
- And I reload and wait for the page
- When I click "#inputs-button"
- Then the "#inputs-description" should be visible
- And I should see "7.0 Liter of food" within "#inputs-description"
- When I click "#product-list"
- Then the "#inputs-description" should not be visible
diff --git a/features/categories_block.feature b/features/categories_block.feature
index 9929de8..de03724 100644
--- a/features/categories_block.feature
+++ b/features/categories_block.feature
@@ -4,16 +4,6 @@ Feature: categories_block
Background:
Given I am on the homepage
- And the following product_categories
- | name | display_in_menu |
- | Food | true |
- | Book | true |
- And the following product_categories
- | parent | name | display_in_menu |
- | Food | Vegetarian | true |
- | Food | Steak | true |
- | Book | Fiction | false |
- | Book | Literature | true |
And the following categories
| name | display_in_menu |
| Wood | true |
@@ -27,49 +17,6 @@ Feature: categories_block
And I go to /admin/environment_design
@selenium
- Scenario: List just product categories
- Given display ".button-bar"
- And I follow "Edit" within ".block-outer .categories-block"
- And I check "Product"
- When I press "Save"
- Then I should see "Food"
- And I should see "Book"
- And "Vegetarian" should not be visible within "span#category-name"
- And "Steak" should not be visible within "span#category-name"
- And "Fiction" should not be visible within "span#category-name"
-
- @selenium
- Scenario: Show submenu if it exists
- Given display ".button-bar"
- And I follow "Edit" within ".block-outer .categories-block"
- And I check "Product"
- And I press "Save"
- And I go to /
- Then I should see "Food"
- And I should see "Book"
- And "Vegetarian" should not be visible within "span#category-name"
- And "Steak" should not be visible within "span#category-name"
- And "Literature" should not be visible within "span#category-name"
- When I follow "block_2_category_2"
- Then I should see "Literature"
- When I follow "block_2_category_1"
- Then I should see "Vegetarian"
- And I should see "Steak"
- And I should not see "Fiction"
-
- @selenium
- Scenario: Show only one submenu per time
- Given display ".button-bar"
- And I follow "Edit" within ".block-outer .categories-block"
- And I check "Product"
- And I press "Save"
- And I go to /
- Then I should see "Book"
- And "Literature" should not be visible within "span#category-name"
- When I follow "block_2_category_2"
- Then I should see "Literature"
-
- @selenium
Scenario: List just general categories
Given display ".button-bar"
And I follow "Edit" within ".block-outer .categories-block"
diff --git a/features/enterprise_homepage.feature b/features/enterprise_homepage.feature
deleted file mode 100644
index 623e4b0..0000000
--- a/features/enterprise_homepage.feature
+++ /dev/null
@@ -1,39 +0,0 @@
-# These tests were originally unit tests, but they were moved here since they are view tests. The originals have been kept just in case somebody wants to review them, but should be removed shortly.
-
-Feature: enterprise homepage
- As a noosfero visitor
- I want to browse an enterprise's homepage
- In order to know more information about the enterprise
-
- Background:
- Given the following users
- | login | name |
- | durdentyler | Tyler Durden |
- And the following enterprises
- | identifier | owner | name | contact_email | contact_phone | enabled |
- | mayhem | durdentyler | Paper Street Soap Co. | queen@workerbees.org | (288) 555-0153 | true |
- And the following enterprise homepage
- | enterprise | name |
- | mayhem | article homepage |
- And the following product_category
- | name |
- | soap |
- And the following product
- | name | category | owner |
- | Natural Handmade | soap | mayhem |
- And feature "products_for_enterprises" is enabled on environment
-
-
- Scenario: display profile info
- When I go to /mayhem/homepage
- Then I should see "queen@workerbees.org"
- And I should see "(288) 555-0153"
-
- Scenario: display products list
- When I go to /mayhem/homepage
- Then I should see "Natural Handmade"
-
- Scenario: display link to product
- When I go to /mayhem/homepage
- And I follow "Natural Handmade"
- Then I should be taken to "Natural Handmade" product page
diff --git a/features/featured_products_block.feature b/features/featured_products_block.feature
deleted file mode 100644
index cddcbab..0000000
--- a/features/featured_products_block.feature
+++ /dev/null
@@ -1,47 +0,0 @@
-Feature: featured_products_block
- As a profile owner
- I want to edit the featured block
-
- Background:
- Given I am on the homepage
- And the following users
- | login | name |
- | eddievedder | Eddie Vedder |
- And the following enterprises
- | identifier | owner | name | enabled |
- | redemoinho | eddievedder | Rede Moinho | true |
- And the following blocks
- | owner | type |
- | redemoinho | FeaturedProductsBlock |
- And the following product_category
- | name |
- | automobile |
- And the following products
- | owner | category | name | description | highlighted |
- | redemoinho | automobile | Car | Red Car | true |
- | redemoinho | automobile | Truck | Blue Truck | true |
- | redemoinho | automobile | Moto | Very long description of and auto-mobile moto to be truncated | true |
- And I am logged in as "eddievedder"
-
- @selenium-fixme
- Scenario: select a product to be featured
- And I follow "Manage my groups"
- And I follow "Control panel of this group"
- And I follow "Edit sideboxes"
- Given I follow "Edit" within ".featured-products-block"
- And I select "Car"
- When I press "Save"
- Then I should see "Car"
- And I should not see "float_to_currency"
- And I should not see "product_path"
-
- @selenium-fixme
- Scenario: display block with long description
- Given I follow "Manage my groups"
- And I follow "Control panel of this group"
- And I follow "Edit sideboxes"
- And I follow "Edit" within ".featured-products-block"
- And I select "Moto"
- And I press "Save"
- When I am on redemoinho's homepage
- Then I should see "Very long description of and auto-mobile moto to b..."
diff --git a/features/search.feature b/features/search.feature
index 271b8d7..a8d3fef 100644
--- a/features/search.feature
+++ b/features/search.feature
@@ -3,9 +3,6 @@ Feature: search
I want to search
In order to find stuff
- Background:
- Given feature "disable_asset_products" is disabled on environment
-
Scenario: show empty results in all enabled assets
Given I go to the search page
And I fill in "search-input" with "Anything"
@@ -18,8 +15,6 @@ Feature: search
And I should see "None" within ".search-results-enterprises"
And I should see "Contents" within ".search-results-articles"
And I should see "None" within ".search-results-articles"
- And I should see "Products" within ".search-results-products"
- And I should see "None" within ".search-results-products"
And I should see "Events" within ".search-results-events"
And I should see "None" within ".search-results-events"
@@ -92,23 +87,6 @@ Feature: search
Then I should see "whales and dolphins" within "div.search-results-articles"
And I should not see "bees and butterflies"
- Scenario: simple search for product
- Given the following enterprises
- | identifier | name |
- | colivre-ent | Colivre |
- And the following product_categories
- | name |
- | Development |
- And the following products
- | owner | category | name |
- | colivre-ent | development | social networks consultancy |
- | colivre-ent | development | wikis consultancy |
- When I go to the search page
- And I fill in "search-input" with "wikis"
- And I press "Search"
- Then I should see "wikis consultancy" within "div.search-results-products"
- And I should not see "social networks consultancy"
-
Scenario: simple search for event
Given the following communities
| identifier | name |
@@ -130,15 +108,8 @@ Feature: search
And the following communities
| identifier | name |
| noosfero-users | Noosfero users |
- And the following product_categories
- | name |
- | Development |
- And the following products
- | owner | name | category |
- | colivre_dev | Noosfero platform | Development |
When I go to the search page
And I fill in "search-input" with "noosfero"
And I press "Search"
Then I should see "Colivre - Noosfero dev." within "div.search-results-enterprises"
And I should see "Noosfero users" within "div.search-results-communities"
- And I should see "Noosfero platform" within "div.search-results-products"
diff --git a/features/search_products.feature b/features/search_products.feature
deleted file mode 100644
index c2aaef1..0000000
--- a/features/search_products.feature
+++ /dev/null
@@ -1,105 +0,0 @@
-Feature: search products
- As a noosfero user
- I want to search products
- In order to find ones that interest me
-
- Background:
- Given feature "disable_asset_products" is disabled on environment
- And the following enterprises
- | identifier | name |
- | colivre-ent | Colivre |
- And the following product_categories
- | name |
- | Development |
- And the following products
- | owner | category | name | price | img |
- | colivre-ent | development | social networks consultancy | 1.00 | fruits |
- | colivre-ent | development | wikis consultancy | 2.00 | shoes |
-
- Scenario: show recent products on index
- When I go to the search products page
- Then I should see "wikis consultancy" within "#search-results"
- And I should see "social networks consultancy" within "#search-results"
-
- Scenario: show empty search results
- When I search products for "something unrelated"
- Then I should see "None" within ".search-results-type-empty"
-
- Scenario: simple search for product
- Given there are no pending jobs
- When I search products for "wikis"
- Then I should see "wikis consultancy" within "#search-results"
- And I should see "wikis consultancy" within ".only-one-result-box"
- And I should see wikis consultancy's product image
- And I should not see "social networks consultancy"
- And I should not see social networks consultancy's product image
-
- Scenario: show percentage (100%) of solidary economy inputs in results
- Given the following inputs
- | product | category | solidary |
- | wikis consultancy | development | true |
- When I go to the search products page
- And I fill in "search-input" with "wikis"
- And I press "Search"
- Then I should see "100%" within "div.search-product-ecosol-percentage-icon-100"
-
- Scenario: show percentage (50%) of solidary economy inputs in results
- Given the following inputs
- | product | category | solidary |
- | wikis consultancy | development | true |
- | wikis consultancy | development | false |
- When I go to the search products page
- And I fill in "search-input" with "wikis"
- And I press "Search"
- Then I should see "50%" within "div.search-product-ecosol-percentage-icon-50"
-
- Scenario: show percentage (75%) of solidary economy inputs in results
- Given the following inputs
- | product | category | solidary |
- | wikis consultancy | development | true |
- | wikis consultancy | development | true |
- | wikis consultancy | development | true |
- | wikis consultancy | development | false |
- When I go to the search products page
- And I fill in "search-input" with "wikis"
- And I press "Search"
- Then I should see "75%" within "div.search-product-ecosol-percentage-icon-75"
-
- Scenario: show percentage (25%) of solidary economy inputs in results
- Given the following inputs
- | product | category | solidary |
- | wikis consultancy | development | true |
- | wikis consultancy | development | false |
- | wikis consultancy | development | false |
- | wikis consultancy | development | false |
- When I go to the search products page
- And I fill in "search-input" with "wikis"
- And I press "Search"
- Then I should see "25%" within "div.search-product-ecosol-percentage-icon-25"
-
- Scenario: display "zoom in" button on images on results
- Given the following products
- | owner | category | name | price | img |
- | colivre-ent | development | noosfero | 12.34 | noosfero-network |
- When I go to the search products page
- And I fill in "search-input" with "noosfero"
- And I press "Search"
- Then I should not see "No image"
- And I should see "Zoom in" within "a.zoomify-image"
-
- Scenario: find products without exact query
- Given the following product_category
- | name |
- | Software Livre |
- And the following products
- | owner | name | category |
- | colivre-ent | Noosfero Social Network Platform | software-livre |
- When I go to the search products page
- And I fill in "search-input" with "Noosfero Social"
- And I press "Search"
- Then I should see "Noosfero Social Network Platform" within "#search-results"
-
- Scenario: don't search when products are disabled in environment
- Given feature "disable_asset_products" is enabled on environment
- When I go to the search products page
- Then I should see "There is no such page" within "#not-found"
diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb
index 619f580..32a91bc 100644
--- a/features/step_definitions/noosfero_steps.rb
+++ b/features/step_definitions/noosfero_steps.rb
@@ -190,37 +190,6 @@ Given /^the following articles? with images?$/ do |table|
end
end
-Given /^the following products?$/ do |table|
- table.hashes.each do |item|
- data = item.dup
- owner = Enterprise[data.delete("owner")]
- category = Category.find_by slug: data.delete("category").to_slug
- data.merge!(:enterprise => owner, :product_category => category)
- if data[:img]
- img = Image.create!(:uploaded_data => fixture_file_upload('/files/'+data.delete("img")+'.png', 'image/png'))
- data.merge!(:image_id => img.id)
- end
- if data[:qualifier]
- qualifier = Qualifier.find_by name: data.delete("qualifier")
- data.merge!(:qualifiers => [qualifier])
- end
- product = Product.create!(data, :without_protection => true)
- end
-end
-
-Given /^the following inputs?$/ do |table|
- table.hashes.each do |item|
- data = item.dup
- product = Product.find_by name: data.delete("product")
- category = Category.find_by slug: data.delete("category").to_slug
- unit = Unit.find_by singular: data.delete("unit")
- solidary = data.delete("solidary")
- input = Input.create!(data.merge(:product => product, :product_category => category, :unit => unit,
- :is_from_solidarity_economy => solidary), :without_protection => true)
- input.update_attribute(:position, data['position'])
- end
-end
-
Given /^the following states$/ do |table|
table.hashes.each do |item|
data = item.dup
@@ -252,39 +221,6 @@ Given /^the following (product_categories|product_category|category|categories|r
end
end
-Given /^the following qualifiers$/ do |table|
- table.hashes.each do |row|
- Qualifier.create!(row.merge(:environment_id => 1), :without_protection => true)
- end
-end
-
-Given /^the following certifiers$/ do |table|
- table.hashes.each do |row|
- row = row.dup
- qualifiers_list = row.delete("qualifiers")
- if qualifiers_list
- row["qualifiers"] = qualifiers_list.split(', ').map{|i| Qualifier.find_by name: i }
- end
- Certifier.create!(row.merge(:environment_id => 1), :without_protection => true)
- end
-end
-
-Given /^the following production costs?$/ do |table|
- table.hashes.map{|item| item.dup}.each do |item|
- owner_type = item.delete('owner')
- owner = owner_type == 'environment' ? Environment.default : Profile[owner_type]
- ProductionCost.create!(item.merge(:owner => owner))
- end
-end
-
-Given /^the following price details?$/ do |table|
- table.hashes.map{|item| item.dup}.each do |item|
- product = Product.find_by name: item.delete('product')
- production_cost = ProductionCost.find_by name: item.delete('production_cost')
- product.price_details.create!(item.merge(:production_cost => production_cost))
- end
-end
-
Given /^I am logged in as "(.+)"$/ do |username|
step %{I go to logout page}
step %{I go to login page}
@@ -574,16 +510,6 @@ When 'I log off' do
visit '/account/logout'
end
-Then /^I should be taken to "([^\"]*)" product page$/ do |product_name|
- product = Product.find_by(name: product_name)
- path = url_for(product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product, :only_path => true))
- if response.class.to_s == 'Webrat::SeleniumResponse'
- URI.parse(response.selenium.get_location).path.should == path_to(path)
- else
- URI.parse(current_url).path.should == path_to(path)
- end
-end
-
Given /^the following enterprise homepages?$/ do |table|
# table is a Cucumber::Ast::Table
table.hashes.each do |item|
@@ -638,24 +564,6 @@ When /^I search ([^\"]*) for "([^\"]*)"$/ do |asset, query|
step %{I press "Search"}
end
-Then /^I should see ([^\"]*)'s product image$/ do |product_name|
- p = Product.find_by name: product_name
- path = url_for(p.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => p))
-
- with_scope('.zoomable-image') do
- page.should have_xpath("a[@href=\"#{path}\"][@class='search-image-pic']")
- end
-end
-
-Then /^I should not see ([^\"]*)'s product image$/ do |product_name|
- p = Product.find_by name: product_name
- path = url_for(p.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => p))
-
- with_scope('.zoomable-image') do
- page.should have_no_xpath("a[@href=\"#{path}\"][@class='search-image-pic']")
- end
-end
-
Then /^I should see ([^\"]*)'s profile image$/ do |name|
page.should have_xpath("//img[@alt=\"#{name}\"]")
end
diff --git a/features/support/paths.rb b/features/support/paths.rb
index 90fee6a..21e79d8 100644
--- a/features/support/paths.rb
+++ b/features/support/paths.rb
@@ -99,9 +99,6 @@ module NavigationHelpers
product = enterprise.products.find_by(name: $2)
'/myprofile/%s/manage_products/show/%s' % [enterprise.identifier, product.id]
- when /^(.*)'s products page$/
- '/catalog/%s' % $1
-
when /^chat$/
'/chat'
diff --git a/lib/noosfero/plugin/routes.rb b/lib/noosfero/plugin/routes.rb
index 0a48b79..4a78bfb 100644
--- a/lib/noosfero/plugin/routes.rb
+++ b/lib/noosfero/plugin/routes.rb
@@ -10,18 +10,22 @@ Dir.glob(Rails.root.join(plugins_root, '*', 'controllers')) do |controllers_dir|
controllers_by_folder = prefixes_by_folder.keys.inject({}) do |hash, folder|
path = "#{controllers_dir}/#{folder}/"
hash[folder] = Dir.glob("#{path}{*.rb,#{plugin_name}_plugin/*.rb}").map do |filename|
- filename.gsub(path, '').gsub(/_controller.rb$/, '')
+ filename.gsub(path, '').gsub /[_\/]controller.rb$/, ''
end
hash
end
controllers_by_folder.each do |folder, controllers|
controllers.each do |controller|
- controller_name = controller.gsub("#{plugin_name}_plugin_",'')
+ controller_name = controller.gsub /#{plugin_name}_plugin[_\/]?/, ''
+ controller_path = if controller_name.present? then "/#{controller_name}" else '' end
+ as = controller.tr '/','_'
if %w[profile myprofile].include?(folder.to_s)
- match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", controller: controller, profile: /#{Noosfero.identifier_format}/i, via: :all
+ match "#{prefixes_by_folder[folder]}/#{plugin_name}#{controller_path}(/:action(/:id))",
+ controller: controller, profile: /#{Noosfero.identifier_format}/i, via: :all, as: as
else
- match "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}(/:action(/:id))", controller: controller, via: :all
+ match "#{prefixes_by_folder[folder]}/#{plugin_name}#{controller_path}(/:action(/:id))",
+ controller: controller, via: :all
end
end
end
diff --git a/plugins/display_content/test/unit/display_content_block_test.rb b/plugins/display_content/test/unit/display_content_block_test.rb
index 5718edd..6f197de 100644
--- a/plugins/display_content/test/unit/display_content_block_test.rb
+++ b/plugins/display_content/test/unit/display_content_block_test.rb
@@ -1,7 +1,7 @@
require_relative '../test_helper'
class DisplayContentBlockTest < ActiveSupport::TestCase
- INVALID_KIND_OF_ARTICLE = [EnterpriseHomepage, Event, RssFeed, UploadedFile, Gallery]
+ INVALID_KIND_OF_ARTICLE = [Event, RssFeed, UploadedFile, Gallery]
VALID_KIND_OF_ARTICLE = [RawHTMLArticle, TextArticle, TextileArticle, TinyMceArticle, Folder, Blog, Forum]
should 'describe itself' do
diff --git a/plugins/orders_cycle/lib/ext/products_plugin/product.rb b/plugins/orders_cycle/lib/ext/products_plugin/product.rb
index 304e18f..aceb717 100644
--- a/plugins/orders_cycle/lib/ext/products_plugin/product.rb
+++ b/plugins/orders_cycle/lib/ext/products_plugin/product.rb
@@ -10,5 +10,7 @@ module ProductsPlugin
has_many :orders_cycles_sales, through: :orders_cycles_items, source: :sale
has_many :orders_cycles_purchases, through: :orders_cycles_items, source: :purchase
+ scope :in_cycle, -> { where type: 'OrdersCyclePlugin::OfferedProduct' }
+
end
end
diff --git a/plugins/orders_cycle/lib/ext/suppliers_plugin/base_product.rb b/plugins/orders_cycle/lib/ext/suppliers_plugin/base_product.rb
deleted file mode 100644
index ccc377e..0000000
--- a/plugins/orders_cycle/lib/ext/suppliers_plugin/base_product.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_dependency 'product'
-
-class Product
-
- scope :in_cycle, -> { where type: 'OrdersCyclePlugin::OfferedProduct' }
-
-end
diff --git a/plugins/products/controllers/profile/products_plugin/catalog_controller.rb b/plugins/products/controllers/profile/products_plugin/catalog_controller.rb
new file mode 100644
index 0000000..27cebab
--- /dev/null
+++ b/plugins/products/controllers/profile/products_plugin/catalog_controller.rb
@@ -0,0 +1,27 @@
+module ProductsPlugin
+ class CatalogController < ProfileController
+
+ before_filter :check_profile
+
+ include CatalogHelper
+
+ def index
+ catalog_load_index
+ end
+
+ protected
+
+ def check_profile
+ return if profile.enterprise?
+ redirect_to controller: 'profile', profile: profile.identifier, action: 'index'
+ end
+
+ # inherit routes from core skipping use_relative_controller!
+ def url_for options
+ options[:controller] = "/#{options[:controller]}" if options.is_a? Hash and options[:controller] and not options[:controller].to_s.starts_with? '/'
+ super options
+ end
+ helper_method :url_for
+
+ end
+end
diff --git a/plugins/products/controllers/profile/products_plugin/page_controller.rb b/plugins/products/controllers/profile/products_plugin/page_controller.rb
new file mode 100644
index 0000000..101d8da
--- /dev/null
+++ b/plugins/products/controllers/profile/products_plugin/page_controller.rb
@@ -0,0 +1,231 @@
+module ProductsPlugin
+ class PageController < ProfileController
+
+ helper ProductsHelper
+
+ protect 'manage_products', :profile, except: [:show]
+ before_filter :login_required, except: [:show]
+ before_filter :create_product?, only: [:new]
+
+ def index
+ @products = @profile.products.paginate(per_page: 10, page: params[:page])
+ end
+
+ def show
+ @product = @profile.products.find(params[:id])
+ @inputs = @product.inputs
+ @allowed_user = user && user.has_permission?('manage_products', profile)
+ end
+
+ def categories_for_selection
+ @category = environment.categories.find_by id: params[:category_id]
+ @object_name = params[:object_name]
+ if @category
+ @categories = @category.children
+ @level = @category.leaf? ? @category.level : @categories.first.level
+ else
+ @categories = ProductCategory.top_level_for(environment)
+ @level = 0
+ end
+ render partial: 'categories_for_selection', locals: { categories: @categories, level: @level }
+ end
+
+ def new
+ @no_design_blocks = true
+ @category = params[:selected_category_id] ? Category.find(params[:selected_category_id]) : nil
+ @product = @profile.products.build(product_category: @category)
+ @categories = ProductCategory.top_level_for(environment)
+ @level = 0
+ if request.post?
+ if @product.save
+ session[:notice] = _('Product succesfully created')
+ render partial: 'shared/redirect_via_javascript',
+ locals: { url: url_for(controller: 'products_plugin/page', action: 'show', id: @product) }
+ else
+ render_dialog_error_messages 'product'
+ end
+ end
+ end
+
+ def edit
+ @product = @profile.products.find(params[:id])
+ field = params[:field]
+ if request.post?
+ begin
+ @product.update!(params[:product])
+ render partial: "display_#{field}", locals: {product: @product}
+ rescue
+ render partial: "edit_#{field}", locals: {product: @product, errors: true}
+ end
+ else
+ render partial: "edit_#{field}", locals: {product: @product, errors: false}
+ end
+ end
+
+ def edit_category
+ @product = @profile.products.find(params[:id])
+ @category = @product.product_category || ProductCategory.first
+ @categories = ProductCategory.top_level_for(environment)
+ @edit = true
+ @level = @category.level
+ if request.post?
+ if @product.update({product_category_id: params[:selected_category_id]}, without_protection: true)
+ render partial: 'shared/redirect_via_javascript',
+ locals: { url: url_for(controller: 'products_plugin/page', action: 'show', id: @product) }
+ else
+ render_dialog_error_messages 'product'
+ end
+ end
+ end
+
+ def show_category_tree
+ @category = environment.categories.find params[:category_id]
+ render partial: 'selected_category_tree'
+ end
+
+ def search_categories
+ @term = params[:term].downcase
+ conditions = ['LOWER(name) LIKE ? OR LOWER(name) LIKE ?', "#{@term}%", "% #{@term}%"]
+ @categories = ProductCategory.where(conditions).limit(10)
+ render json: (@categories.map do |category|
+ {label: category.name, value: category.id}
+ end)
+ end
+
+ def add_input
+ @product = @profile.products.find(params[:id])
+ @input = @product.inputs.build
+ @categories = ProductCategory.top_level_for(environment)
+ @level = 0
+ if request.post?
+ if @input.update(product_category_id: params[:selected_category_id])
+ @inputs = @product.inputs
+ render partial: 'display_inputs'
+ else
+ render_dialog_error_messages 'product'
+ end
+ else
+ render partial: 'add_input'
+ end
+ end
+
+ def manage_product_details
+ @product = @profile.products.find(params[:id])
+ if request.post?
+ @product.update_price_details(params[:price_details]) if params[:price_details]
+ render partial: 'display_price_details'
+ else
+ render partial: 'manage_product_details'
+ end
+ end
+
+ def remove_price_detail
+ @product = @profile.products.find(params[:product])
+ @price_detail = @product.price_details.find(params[:id])
+ @product = @price_detail.product
+ if request.post?
+ @price_detail.destroy
+ render nothing: true
+ end
+ end
+
+ def display_price_composition_bar
+ @product = @profile.products.find(params[:id])
+ render partial: 'price_composition_bar'
+ end
+
+ def display_inputs_cost
+ @product = @profile.products.find(params[:id])
+ render inline: "<%= float_to_currency(@product.inputs_cost) %>"
+ end
+
+ def destroy
+ @product = @profile.products.find(params[:id])
+ if @product.destroy
+ session[:notice] = _('Product succesfully removed')
+ redirect_back_or_default action: 'index'
+ else
+ session[:notice] = _('Could not remove the product')
+ redirect_back_or_default action: 'show', id: @product
+ end
+ end
+
+ def edit_input
+ if request.xhr?
+ @input = @profile.inputs.find_by id: params.fetch(:id)
+ if @input
+ if request.post?
+ if @input.update(params[:input])
+ render partial: 'display_input', locals: {input: @input}
+ else
+ render partial: 'edit_input'
+ end
+ else
+ render partial: 'edit_input'
+ end
+ else
+ render text: _('The input was not found')
+ end
+ end
+ end
+
+ def order_inputs
+ @product = @profile.products.find(params[:id])
+ @product.order_inputs!(params[:input]) if params[:input]
+ render nothing: true
+ end
+
+ def remove_input
+ @input = @profile.inputs.find(params[:id])
+ @product = @input.product
+ if request.post?
+ if @input.destroy
+ @inputs = @product.inputs
+ render partial: 'display_inputs'
+ else
+ render_dialog_error_messages 'input'
+ end
+ end
+ end
+
+ def certifiers_for_selection
+ @qualifier = Qualifier.where(id: params[:id]).first
+ render :update do |page|
+ page.replace_html params[:certifier_area], partial: 'certifiers_for_selection'
+ end
+ end
+
+ def create_production_cost
+ cost = @profile.production_costs.create(name: params[:id])
+ if cost.valid?
+ cost.save
+ render text: {name: cost.name,
+ id: cost.id,
+ ok: true
+ }.to_json
+ else
+ render text: {
+ ok: false,
+ error_msg: _(cost.errors['name'].join('\n')) % {fn: _('Name')}
+ }.to_json
+ end
+ end
+
+ protected
+
+ def create_product?
+ if !profile.create_product?
+ render_access_denied
+ return
+ end
+ end
+
+ # inherit routes from core skipping use_relative_controller!
+ def url_for options
+ options[:controller] = "/#{options[:controller]}" if options.is_a? Hash and options[:controller] and not options[:controller].to_s.starts_with? '/'
+ super options
+ end
+ helper_method :url_for
+
+ end
+end
diff --git a/plugins/products/controllers/public/products_plugin/search_controller.rb b/plugins/products/controllers/public/products_plugin/search_controller.rb
new file mode 100644
index 0000000..a6bbeec
--- /dev/null
+++ b/plugins/products/controllers/public/products_plugin/search_controller.rb
@@ -0,0 +1,21 @@
+module ProductsPlugin
+ class SearchController < ::SearchController
+
+ helper ProductsHelper
+
+ def products
+ @scope = @environment.products
+ full_text_search
+ end
+
+ protected
+
+ # inherit routes from core skipping use_relative_controller!
+ def url_for options
+ options[:controller] = "/#{options[:controller]}" if options.is_a? Hash and options[:controller] and not options[:controller].to_s.starts_with? '/'
+ super options
+ end
+ helper_method :url_for
+
+ end
+end
diff --git a/plugins/products/features/browse_catalogs.feature b/plugins/products/features/browse_catalogs.feature
new file mode 100644
index 0000000..e291cdd
--- /dev/null
+++ b/plugins/products/features/browse_catalogs.feature
@@ -0,0 +1,317 @@
+Feature: browse catalogs
+ As a noosfero visitor
+ I want to browse catalogs of products
+
+ Background:
+ Given the following users
+ | login | name |
+ | joaosilva | Joao Silva |
+ And the following enterprises
+ | identifier | owner | name | enabled |
+ | artebonito | joaosilva | Associação de Artesanato de Bonito | true |
+ And feature "products_for_enterprises" is enabled on environment
+ And the following product_categories
+ | name |
+ | categ1 |
+ | food |
+ And I am on /catalog/artebonito
+
+ Scenario: display titles
+ Then the page title should be "Associação de Artesanato de Bonito"
+ And I should see "Products/Services"
+
+ Scenario: display the simplest possible product
+ Given the following products
+ | owner | category |
+ | artebonito | categ1 |
+ And I am on /catalog/artebonito
+ Then I should see "categ1" within "li.product-link"
+ And I should see "No image" within ".no-image"
+ And I should not see "unit" within "#product-list"
+ And I should not see "product unavailable"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: display a simple product without price
+ Given the following products
+ | owner | category | name |
+ | artebonito | categ1 | Produto1 |
+ And I am on /catalog/artebonito
+ Then I should see "Produto1" within "li.product-link"
+ And I should see "No image" within ".no-image"
+ And I should not see "unit" within "#product-list"
+ And I should not see "product unavailable"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: display a simple product without details
+ Given the following products
+ | owner | category | name | price |
+ | artebonito | categ1 | Produto1 | 50.00 |
+ And I am on /catalog/artebonito
+ Then I should see "Produto1" within "li.product-link"
+ And I should see "50.00" within "span.product-price"
+ And I should see "unit" within "span.product-unit"
+ And I should see "No image" within ".no-image"
+ And I should not see "product unavailable"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: don't display the price when it's $0.00
+ Given the following products
+ | owner | category | name | price |
+ | artebonito | categ1 | Produto1 | 0.00 |
+ And I am on /catalog/artebonito
+ Then I should see "Produto1" within "li.product-link"
+ And I should not see "0.00"
+
+ Scenario: don't display the price when it's not defined
+ Given the following products
+ | owner | category | name |
+ | artebonito | categ1 | Produto1 |
+ And I am on /catalog/artebonito
+ Then I should see "Produto1" within "li.product-link"
+ And I should not see "0.00"
+ And I should see "No image" within ".no-image"
+ And I should not see "product unavailable"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: product name links to product page
+ Given the following products
+ | owner | category | name | price |
+ | artebonito | categ1 | Produto1 | 50.00 |
+ And I am on /catalog/artebonito
+ When I follow "Produto1" within "li.product-link"
+ Then I should be taken to "Produto1" product page
+
+ Scenario: display product with custom image
+ Given the following products
+ | owner | category | name | price | img |
+ | artebonito | categ1 | Agrotox | 12.34 | agrotox |
+ And I am on /catalog/artebonito
+ Then I should see "Agrotox" within "li.product-link"
+ And I should see "12.34" within "span.product-price"
+ And I should see "unit" within "span.product-unit"
+ And I should not see "No image"
+ And I should not see "product unavailable"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: display "zoom in" button
+ Given the following products
+ | owner | category | name | price | img |
+ | artebonito | categ1 | Agrotox | 12.34 | agrotox |
+ And I am on /catalog/artebonito
+ And I should not see "No image"
+ And I should see "Zoom in" within ".zoomify-image"
+
+ Scenario: image links to product page
+ Given the following products
+ | owner | category | name | price | img |
+ | artebonito | categ1 | Agrotox | 12.34 | agrotox |
+ And I am on /catalog/artebonito
+ When I follow "Agrotox" within ".product-image-link"
+ Then I should be taken to "Agrotox" product page
+
+ Scenario: display product with discount
+ Given the following products
+ | owner | category | name | price | discount | img |
+ | artebonito | categ1 | Semterrinha | 99.99 | 12.34 | semterrinha |
+ And I am on /catalog/artebonito
+ Then I should see "Semterrinha" within "li.product-link"
+ And I should see "99.99" within "span.product-discount"
+ And I should see "87.65" within "span.product-price"
+ And I should not see "No image"
+ And I should not see "description"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ @selenium-fixme
+ Scenario: display description button when needed (but not the description)
+ Given the following products
+ | owner | category | name | price | description |
+ | artebonito | categ1 | Produto2 | 12.34 | A small description for a product that doesn't exist. |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ Then I should see "Produto2" within "li.product-link"
+ And I should see "12.34" within "span.product-price"
+ And I should see "description" within "#product-description-button"
+ And "description" should not be visible within "product-description-button"
+ And I should see "A small description" within "#product-description"
+ And "A small description for a product that doesn't exist" should not be visible within "product-description"
+
+ @selenium-fixme
+ Scenario: display description when button is clicked
+ Given the following products
+ | owner | category | name | price | description |
+ | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ When I follow "product-description-button"
+ Then I should see "A small description" within "#product-description"
+ And "A small description for a product that doesn't exist" should not be visible within "product-description"
+
+ @selenium-fixme
+ Scenario: hide description
+ Given the following products
+ | owner | category | name | price | description |
+ | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ When I click "product-description-button"
+ Then I should see "A small description" within "#product-description"
+ And the "product-description" should be visible
+ When I click "product-list"
+ Then the "product-description" should not be visible
+
+ Scenario: display unavailable product
+ Given the following products
+ | owner | category | name | price | available |
+ | artebonito | categ1 | Prod3 | 12.34 | false |
+ And I am on /catalog/artebonito
+ Then I should see "Prod3" within "li.not-available"
+ And I should see "12.34" within "li.not-available"
+ And I should see "product unavailable" within "li.product-unavailable"
+ And I should not see "qualifiers"
+ And I should not see "price composition"
+
+ Scenario: display qualifiers
+ Given the following qualifiers
+ | name |
+ | Organic |
+ And the following certifiers
+ | name | qualifiers |
+ | Colivre | Organic |
+ And the following products
+ | owner | category | name | price | qualifier |
+ | artebonito | categ1 | Banana | 0.99 | Organic |
+ And I am on /catalog/artebonito
+ Then I should see "Banana" within "li.product-link"
+ And I should see "0.99" within "span.product-price"
+ And I should see "qualifiers" within "li.product-qualifiers"
+ And I should see "Organic" within "span.search-product-qualifier"
+ And I should not see "price composition"
+
+ @selenium-fixme
+ Scenario: not display price composition button if price is not described
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Bananada | 10.00 |
+ And the following input
+ | product | category | price_per_unit | amount_used |
+ | Bananada | food | 0.99 | 5 |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ Then I should see "Bananada" within "li.product-link"
+ And I should see "10.00" within "span.product-price"
+ And the "#product-price-composition-button" should not be visible
+
+ @selenium-fixme
+ Scenario: display price composition button (but not inputs)
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Bananada | 10.00 |
+ And the following input
+ | product | category | price_per_unit | amount_used |
+ | Bananada | food | 2.00 | 5 |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ Then I should see "Bananada" within "li.product-link"
+ And I should see "10.00" within "span.product-price"
+ And I should see "price composition" within "#product-price-composition-button"
+ And the "#product-price-composition-button" should be visible
+ And I should see "food" within "#product-price-composition"
+ And I should see "10.00" within "#product-price-composition"
+
+ @selenium-fixme
+ Scenario: display price composition when button is clicked
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Bananada | 10.88 |
+ And the following input
+ | product | category | price_per_unit | amount_used |
+ | Bananada | food | 2.72 | 4 |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ When I click "#product-price-composition-button"
+ Then the "#product-price-composition" should be visible
+ And I should see "food" within "#product-price-composition"
+ And I should see "10.88" within "#product-price-composition"
+
+ @selenium-fixme
+ Scenario: display inputs and raw materials button when not completely filled
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Vitamina | 17.99 |
+ And the following unit
+ | name | plural |
+ | Liter | Liters |
+ And the following input
+ | product | category |
+ | Vitamina | food |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ Then the "#inputs-button" should be visible
+ And I should see "inputs and raw materials" within "#inputs-button"
+
+ @selenium-fixme
+ Scenario: display inputs and raw materials button
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Vitamina | 17.99 |
+ And the following unit
+ | name | plural |
+ | Liter | Liters |
+ And the following input
+ | product | category | price_per_unit | amount_used | unit |
+ | Vitamina | food | 1.45 | 7 | Liter |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ Then I should see "Vitamina" within "li.product-link"
+ And I should see "17.99" within "span.product-price"
+ And the "#inputs-button" should be visible
+ And I should see "inputs and raw materials" within "#inputs-button"
+ And the "#inputs-description" should not be visible
+ And I should see "7.0 Liter of food" within "#inputs-description"
+
+ @selenium-fixme
+ Scenario: display inputs and raw materials description
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Vitamina | 17.99 |
+ And the following unit
+ | name | plural |
+ | Liter | Liters |
+ And the following input
+ | product | category | price_per_unit | amount_used | unit |
+ | Vitamina | food | 1.45 | 7 | Liter |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ When I click "#inputs-button"
+ Then the "#inputs-description" should be visible
+ And I should see "7.0 Liter of food" within "#inputs-description"
+
+ @selenium-fixme
+ Scenario: hide inputs and raw materials
+ Given the following product
+ | owner | category | name | price |
+ | artebonito | food | Vitamina | 17.99 |
+ And the following unit
+ | name | plural |
+ | Liter | Liters |
+ And the following input
+ | product | category | price_per_unit | amount_used | unit |
+ | Vitamina | food | 1.45 | 7 | Liter |
+ And I am on /catalog/artebonito
+ And I reload and wait for the page
+ When I click "#inputs-button"
+ Then the "#inputs-description" should be visible
+ And I should see "7.0 Liter of food" within "#inputs-description"
+ When I click "#product-list"
+ Then the "#inputs-description" should not be visible
diff --git a/plugins/products/features/enterprise_homepage.feature b/plugins/products/features/enterprise_homepage.feature
new file mode 100644
index 0000000..ec6ac6c
--- /dev/null
+++ b/plugins/products/features/enterprise_homepage.feature
@@ -0,0 +1,37 @@
+# These tests were originally unit tests, but they were moved here since they are view tests. The originals have been kept just in case somebody wants to review them, but should be removed shortly.
+
+Feature: enterprise homepage
+ As a noosfero visitor
+ I want to browse an enterprise's homepage
+ In order to know more information about the enterprise
+
+ Background:
+ Given the following users
+ | login | name |
+ | durdentyler | Tyler Durden |
+ And the following enterprises
+ | identifier | owner | name | contact_email | contact_phone | enabled |
+ | mayhem | durdentyler | Paper Street Soap Co. | queen@workerbees.org | (288) 555-0153 | true |
+ And the following enterprise homepage
+ | enterprise | name |
+ | mayhem | article homepage |
+ And the following product_category
+ | name |
+ | soap |
+ And the following product
+ | name | category | owner |
+ | Natural Handmade | soap | mayhem |
+
+ Scenario: display profile info
+ When I go to /mayhem/homepage
+ Then I should see "queen@workerbees.org"
+ And I should see "(288) 555-0153"
+
+ Scenario: display products list
+ When I go to /mayhem/homepage
+ Then I should see "Natural Handmade"
+
+ Scenario: display link to product
+ When I go to /mayhem/homepage
+ And I follow "Natural Handmade"
+ Then I should be taken to "Natural Handmade" product page
diff --git a/plugins/products/features/featured_products_block.feature b/plugins/products/features/featured_products_block.feature
new file mode 100644
index 0000000..cddcbab
--- /dev/null
+++ b/plugins/products/features/featured_products_block.feature
@@ -0,0 +1,47 @@
+Feature: featured_products_block
+ As a profile owner
+ I want to edit the featured block
+
+ Background:
+ Given I am on the homepage
+ And the following users
+ | login | name |
+ | eddievedder | Eddie Vedder |
+ And the following enterprises
+ | identifier | owner | name | enabled |
+ | redemoinho | eddievedder | Rede Moinho | true |
+ And the following blocks
+ | owner | type |
+ | redemoinho | FeaturedProductsBlock |
+ And the following product_category
+ | name |
+ | automobile |
+ And the following products
+ | owner | category | name | description | highlighted |
+ | redemoinho | automobile | Car | Red Car | true |
+ | redemoinho | automobile | Truck | Blue Truck | true |
+ | redemoinho | automobile | Moto | Very long description of and auto-mobile moto to be truncated | true |
+ And I am logged in as "eddievedder"
+
+ @selenium-fixme
+ Scenario: select a product to be featured
+ And I follow "Manage my groups"
+ And I follow "Control panel of this group"
+ And I follow "Edit sideboxes"
+ Given I follow "Edit" within ".featured-products-block"
+ And I select "Car"
+ When I press "Save"
+ Then I should see "Car"
+ And I should not see "float_to_currency"
+ And I should not see "product_path"
+
+ @selenium-fixme
+ Scenario: display block with long description
+ Given I follow "Manage my groups"
+ And I follow "Control panel of this group"
+ And I follow "Edit sideboxes"
+ And I follow "Edit" within ".featured-products-block"
+ And I select "Moto"
+ And I press "Save"
+ When I am on redemoinho's homepage
+ Then I should see "Very long description of and auto-mobile moto to b..."
diff --git a/plugins/products/features/search_products.feature b/plugins/products/features/search_products.feature
new file mode 100644
index 0000000..5b95939
--- /dev/null
+++ b/plugins/products/features/search_products.feature
@@ -0,0 +1,108 @@
+Feature: search products
+ As a noosfero user
+ I want to search products
+ In order to find ones that interest me
+
+ Background:
+ Given feature "disable_asset_products" is disabled on environment
+ And the following enterprises
+ | identifier | name |
+ | colivre-ent | Colivre |
+ And the following product_categories
+ | name |
+ | Development |
+ And the following products
+ | owner | category | name | price | img |
+ | colivre-ent | development | social networks consultancy | 1.00 | fruits |
+ | colivre-ent | development | wikis consultancy | 2.00 | shoes |
+
+ Scenario: show recent products on index
+ When I go to the search products page
+ Then I should see "wikis consultancy" within "#search-results"
+ And I should see "social networks consultancy" within "#search-results"
+
+ Scenario: show empty search results
+ When I search products for "something unrelated"
+ Then I should see "None" within ".search-results-type-empty"
+
+ Scenario: simple search for product
+ Given there are no pending jobs
+ When I search products for "wikis"
+ Then I should see "wikis consultancy" within "#search-results"
+ And I should see "wikis consultancy" within ".only-one-result-box"
+ And I should see wikis consultancy's product image
+ And I should not see "social networks consultancy"
+ And I should not see social networks consultancy's product image
+
+ Scenario: show percentage (100%) of solidary economy inputs in results
+ Given the following inputs
+ | product | category | solidary |
+ | wikis consultancy | development | true |
+ When I go to the search products page
+ And I fill in "search-input" with "wikis"
+ And I press "Search"
+ Then I should see "100%" within "div.search-product-ecosol-percentage-icon-100"
+
+ Scenario: show percentage (50%) of solidary economy inputs in results
+ Given the following inputs
+ | product | category | solidary |
+ | wikis consultancy | development | true |
+ | wikis consultancy | development | false |
+ When I go to the search products page
+ And I fill in "search-input" with "wikis"
+ And I press "Search"
+ Then I should see "50%" within "div.search-product-ecosol-percentage-icon-50"
+
+ Scenario: show percentage (75%) of solidary economy inputs in results
+ Given the following inputs
+ | product | category | solidary |
+ | wikis consultancy | development | true |
+ | wikis consultancy | development | true |
+ | wikis consultancy | development | true |
+ | wikis consultancy | development | false |
+ When I go to the search products page
+ And I fill in "search-input" with "wikis"
+ And I press "Search"
+ Then I should see "75%" within "div.search-product-ecosol-percentage-icon-75"
+
+ Scenario: show percentage (25%) of solidary economy inputs in results
+ Given the following inputs
+ | product | category | solidary |
+ | wikis consultancy | development | true |
+ | wikis consultancy | development | false |
+ | wikis consultancy | development | false |
+ | wikis consultancy | development | false |
+ When I go to the search products page
+ And I fill in "search-input" with "wikis"
+ And I press "Search"
+ Then I should see "25%" within "div.search-product-ecosol-percentage-icon-25"
+
+ Scenario: display "zoom in" button on images on results
+ Given the following products
+ | owner | category | name | price | img |
+ | colivre-ent | development | noosfero | 12.34 | noosfero-network |
+ When I go to the search products page
+ And I fill in "search-input" with "noosfero"
+ And I press "Search"
+ Then I should not see "No image"
+ And I should see "Zoom in" within "a.zoomify-image"
+
+ Scenario: find products without exact query
+ Given the following product_category
+ | name |
+ | Software Livre |
+ And the following products
+ | owner | name | category |
+ | colivre-ent | Noosfero Social Network Platform | software-livre |
+ When I go to the search products page
+ And I fill in "search-input" with "Noosfero Social"
+ And I press "Search"
+ Then I should see "Noosfero Social Network Platform" within "#search-results"
+
+ Scenario: simple search for product
+ When I go to the search products page
+ And I fill in "search-input" with "wikis"
+ And I press "Search"
+ Then I should see "wikis consultancy" within "div.search-results-products"
+ And I should not see "social networks consultancy"
+
diff --git a/plugins/products/features/step_definitions/products_steps.rb b/plugins/products/features/step_definitions/products_steps.rb
new file mode 100644
index 0000000..1f68db5
--- /dev/null
+++ b/plugins/products/features/step_definitions/products_steps.rb
@@ -0,0 +1,92 @@
+Then /^I should be taken to "([^\"]*)" product page$/ do |product_name|
+ product = Product.find_by name: product_name
+ path = url_for(product.enterprise.public_profile_url.merge(controller: 'products_plugin/page', action: 'show', id: product, only_path: true))
+ if response.class.to_s == 'Webrat::SeleniumResponse'
+ URI.parse(response.selenium.get_location).path.should == path_to(path)
+ else
+ URI.parse(current_url).path.should == path_to(path)
+ end
+end
+
+Then /^I should see ([^\"]*)'s product image$/ do |product_name|
+ p = Product.find_by name: product_name
+ path = url_for(p.enterprise.public_profile_url.merge(controller: 'products_plugin/page', action: 'show', id: p))
+
+ with_scope('.zoomable-image') do
+ page.should have_xpath("a[@href=\"#{path}\"][@class='search-image-pic']")
+ end
+end
+
+Then /^I should not see ([^\"]*)'s product image$/ do |product_name|
+ p = Product.find_by name: product_name
+ path = url_for(p.enterprise.public_profile_url.merge(controller: 'products_plugin/page', action: 'show', id: p))
+
+ with_scope('.zoomable-image') do
+ page.should have_no_xpath("a[@href=\"#{path}\"][@class='search-image-pic']")
+ end
+end
+
+Given /^the following products?$/ do |table|
+ table.hashes.each do |item|
+ data = item.dup
+ owner = Enterprise[data.delete("owner")]
+ category = Category.find_by slug: data.delete("category").to_slug
+ data.merge!(enterprise: owner, product_category: category)
+ if data[:img]
+ img = Image.create!(uploaded_data: fixture_file_upload('/files/'+data.delete("img")+'.png', 'image/png'))
+ data.merge!(image_id: img.id)
+ end
+ if data[:qualifier]
+ qualifier = Qualifier.find_by name: data.delete("qualifier")
+ data.merge!(qualifiers: [qualifier])
+ end
+ product = Product.create!(data, without_protection: true)
+ end
+end
+
+Given /^the following inputs?$/ do |table|
+ table.hashes.each do |item|
+ data = item.dup
+ product = Product.find_by name: data.delete("product")
+ category = Category.find_by slug: data.delete("category").to_slug
+ unit = Unit.find_by singular: data.delete("unit")
+ solidary = data.delete("solidary")
+ input = Input.create!(data.merge(product: product, product_category: category, unit: unit,
+ is_from_solidarity_economy: solidary), without_protection: true)
+ input.update_attribute(:position, data['position'])
+ end
+end
+
+Given /^the following production costs?$/ do |table|
+ table.hashes.map{|item| item.dup}.each do |item|
+ owner_type = item.delete('owner')
+ owner = owner_type == 'environment' ? Environment.default : Profile[owner_type]
+ ProductionCost.create!(item.merge(owner: owner))
+ end
+end
+
+Given /^the following price details?$/ do |table|
+ table.hashes.map{|item| item.dup}.each do |item|
+ product = Product.find_by name: item.delete('product')
+ production_cost = ProductionCost.find_by name: item.delete('production_cost')
+ product.price_details.create!(item.merge(production_cost: production_cost))
+ end
+end
+
+Given /^the following qualifiers$/ do |table|
+ table.hashes.each do |row|
+ Qualifier.create!(row.merge(environment_id: 1), without_protection: true)
+ end
+end
+
+Given /^the following certifiers$/ do |table|
+ table.hashes.each do |row|
+ row = row.dup
+ qualifiers_list = row.delete("qualifiers")
+ if qualifiers_list
+ row["qualifiers"] = qualifiers_list.split(', ').map{ |i| Qualifier.find_by name: i }
+ end
+ Certifier.create!(row.merge(environment_id: 1), without_protection: true)
+ end
+end
+
diff --git a/plugins/products/features/support/paths.rb b/plugins/products/features/support/paths.rb
new file mode 100644
index 0000000..42e9e44
--- /dev/null
+++ b/plugins/products/features/support/paths.rb
@@ -0,0 +1,15 @@
+module NavigationHelpers
+ module ProductsPlugin
+ def path_to page_name
+ case page_name
+ when /^(.*)'s products page$/
+ '/catalog/%s' % $1
+ else
+ super
+ end
+ end
+ end
+
+ prepend ProductsPlugin
+end
+
diff --git a/plugins/products/lib/ext/action_tracker_config.rb b/plugins/products/lib/ext/action_tracker_config.rb
new file mode 100644
index 0000000..7c18263
--- /dev/null
+++ b/plugins/products/lib/ext/action_tracker_config.rb
@@ -0,0 +1,12 @@
+ActionTrackerConfig.verbs.merge!({
+
+ create_product: {
+ },
+
+ update_product: {
+ },
+
+ remove_product: {
+ },
+
+})
diff --git a/plugins/products/lib/ext/action_tracker_helper.rb b/plugins/products/lib/ext/action_tracker_helper.rb
new file mode 100644
index 0000000..4bb1bf3
--- /dev/null
+++ b/plugins/products/lib/ext/action_tracker_helper.rb
@@ -0,0 +1,23 @@
+require_dependency 'action_tracker_helper'
+
+module ActionTrackerHelper
+
+ def create_product_description ta
+ _('created the product %{title}') % {
+ title: link_to(truncate(ta.get_name), ta.get_url),
+ }
+ end
+
+ def update_product_description ta
+ _('updated the product %{title}') % {
+ title: link_to(truncate(ta.get_name), ta.get_url),
+ }
+ end
+
+ def remove_product_description ta
+ _('removed the product %{title}') % {
+ title: truncate(ta.get_name),
+ }
+ end
+
+end
diff --git a/plugins/products/lib/ext/categories_helper.rb b/plugins/products/lib/ext/categories_helper.rb
new file mode 100644
index 0000000..b53dde5
--- /dev/null
+++ b/plugins/products/lib/ext/categories_helper.rb
@@ -0,0 +1,7 @@
+require_dependency 'categories_helper'
+
+module CategoriesHelper
+
+ TYPES << [ _('Product Category'), ProductCategory.to_s ]
+
+end
diff --git a/plugins/products/lib/ext/enterprise.rb b/plugins/products/lib/ext/enterprise.rb
new file mode 100644
index 0000000..c3ce1fc
--- /dev/null
+++ b/plugins/products/lib/ext/enterprise.rb
@@ -0,0 +1,41 @@
+require_dependency 'enterprise'
+
+class Enterprise
+
+ attr_accessible :products_per_catalog_page
+
+ settings_items :products_per_catalog_page, type: :integer, default: 6
+ alias_method :products_per_catalog_page_before_type_cast, :products_per_catalog_page
+ validates_numericality_of :products_per_catalog_page, allow_nil: true, greater_than: 0
+
+ def highlighted_products_with_image(options = {})
+ Product.where(highlighted: true).joins(:image)
+ end
+
+ def default_set_of_blocks
+ links = [
+ {name: _("Enterprises's profile"), address: '/profile/{profile}', icon: 'ok'},
+ {name: _('Blog'), address: '/{profile}/blog', icon: 'edit'},
+ {name: _('Products'), address: '/profile/{profile}/plugin/products/catalog', icon: 'new'},
+ ]
+ blocks = [
+ [MainBlock.new],
+ [ ProfileImageBlock.new,
+ LinkListBlock.new(links: links),
+ ProductCategoriesBlock.new
+ ],
+ [LocationBlock.new]
+ ]
+ blocks[2].unshift ProductsBlock.new
+ blocks
+ end
+
+ def catalog_url
+ {profile: identifier, controller: 'products_plugin/catalog'}
+ end
+
+ def create_product?
+ true
+ end
+
+end
diff --git a/plugins/products/lib/ext/environment.rb b/plugins/products/lib/ext/environment.rb
new file mode 100644
index 0000000..9b5bc11
--- /dev/null
+++ b/plugins/products/lib/ext/environment.rb
@@ -0,0 +1,20 @@
+require_dependency 'environment'
+
+class Environment
+
+ has_many :production_costs, class_name: 'ProductsPlugin::ProductionCost', as: :owner
+
+ has_many :product_categories, class_name: 'ProductsPlugin::ProductCategory'
+
+ has_many :products, through: :profiles
+
+ has_many :qualifiers, class_name: 'ProductsPlugin::Qualifier'
+ has_many :certifiers, class_name: 'ProductsPlugin::Certifier'
+
+ has_many :units, -> { order 'position' }, class_name: 'ProductsPlugin::Unit'
+
+ def highlighted_products_with_image(options = {})
+ self.products.where(highlighted: true).joins(:image).order('created_at ASC')
+ end
+
+end
diff --git a/plugins/products/lib/ext/profile.rb b/plugins/products/lib/ext/profile.rb
new file mode 100644
index 0000000..c9f8454
--- /dev/null
+++ b/plugins/products/lib/ext/profile.rb
@@ -0,0 +1,10 @@
+require_dependency 'profile'
+
+class Profile
+
+ has_many :products, foreign_key: :profile_id, dependent: :destroy, class_name: 'ProductsPlugin::Product'
+ has_many :product_categories, through: :products, class_name: 'ProductsPlugin::ProductCategory'
+ has_many :inputs, through: :products, class_name: 'ProductsPlugin::Input'
+ has_many :production_costs, as: :owner, class_name: 'ProductsPlugin::ProductionCost'
+
+end
diff --git a/plugins/products/lib/products_plugin.rb b/plugins/products/lib/products_plugin.rb
new file mode 100644
index 0000000..3aa3fba
--- /dev/null
+++ b/plugins/products/lib/products_plugin.rb
@@ -0,0 +1,14 @@
+module ProductsPlugin
+
+ extend Noosfero::Plugin::ParentMethods
+
+ def self.plugin_name
+ I18n.t'products_plugin.lib.plugin.name'
+ end
+
+ def self.plugin_description
+ I18n.t'products_plugin.lib.plugin.description'
+ end
+
+end
+
diff --git a/plugins/products/lib/products_plugin/base.rb b/plugins/products/lib/products_plugin/base.rb
new file mode 100644
index 0000000..9ca186e
--- /dev/null
+++ b/plugins/products/lib/products_plugin/base.rb
@@ -0,0 +1,57 @@
+module ProductsPlugin
+ class Base < Noosfero::Plugin
+
+ def stylesheet?
+ true
+ end
+
+ def js_files
+ %w[products].map{ |j| "javascripts/#{j}" }
+ end
+
+ def self.extra_blocks
+ {
+ ProductsBlock => {type: [Enterprise] },
+ }
+ end
+
+ def control_panel_buttons
+ {
+ title: _('Manage Products/Services'),
+ icon: 'suppliers-manage-suppliers',
+ url: {controller: 'products_plugin/page'},
+ } if profile.enterprise?
+ end
+
+ def profile_info_extra_contents
+ lambda do
+ render 'profile_editor/products_profile_info_contents'
+ end
+ end
+
+ def content_types
+ [EnterpriseHomepage] if context.profile.enterprise?
+ end
+
+ end
+end
+
+# STI compatibility
+Product = ProductsPlugin::Product
+ProductsBlock = ProductsPlugin::ProductsBlock
+ProductCategoriesBlock = ProductsPlugin::ProductCategoriesBlock
+ProductCategory = ProductsPlugin::ProductCategory
+FeaturedProductsBlock = ProductsPlugin::FeaturedProductsBlock
+
+# compatibility
+Unit = ProductsPlugin::Unit
+Input = ProductsPlugin::Input
+Qualifier = ProductsPlugin::Qualifier
+Certifier = ProductsPlugin::Certifier
+QualifierCertifier = ProductsPlugin::QualifierCertifier
+ProductQualifier = ProductsPlugin::ProductQualifier
+ProductionCost = ProductsPlugin::ProductionCost
+PriceDetail = ProductsPlugin::PriceDetail
+
+EnterpriseHomepage = ProductsPlugin::EnterpriseHomepage
+
diff --git a/plugins/products/lib/products_plugin/catalog_helper.rb b/plugins/products/lib/products_plugin/catalog_helper.rb
new file mode 100644
index 0000000..01c867c
--- /dev/null
+++ b/plugins/products/lib/products_plugin/catalog_helper.rb
@@ -0,0 +1,47 @@
+module ProductsPlugin::CatalogHelper
+
+ include DisplayHelper
+ include ProductsPlugin::ProductsHelper
+
+ protected
+
+ def catalog_load_index options = {page: params[:page], show_categories: true}
+ if options[:show_categories]
+ @category = params[:level] ? ProductCategory.find(params[:level]) : nil
+ @categories = ProductCategory.on_level(params[:level]).order(:name)
+ end
+
+ @products = profile.products.from_category(@category).
+ reorder('available desc, highlighted desc, name asc').
+ paginate(per_page: @profile.products_per_catalog_page, page: options[:page])
+ end
+
+ def breadcrumb(category)
+ start = link_to(_('Start'), {controller: 'products_plugin/catalog', action: 'index'})
+ ancestors = category.ancestors.map { |c| link_to(c.name, {controller: 'products_plugin/catalog', action: 'index', level: c.id}) }.reverse
+ current_level = content_tag('strong', category.name)
+ all_items = [start] + ancestors + [current_level]
+ content_tag('div', safe_join(all_items, ' → '), id: 'breadcrumb')
+ end
+
+ def category_link(category)
+ count = profile.products.from_category(category).count
+ name = truncate(category.name, length: 22 - count.to_s.size)
+ link = link_to(name, {controller: 'products_plugin/catalog', action: 'index', level: category.id}, title: category.name)
+ content_tag('div', "#{link} #{count} ".html_safe) if count > 0
+ end
+
+ def category_with_sub_list(category)
+ content_tag 'li', "#{category_link(category)}\n#{sub_category_list(category)}".html_safe
+ end
+
+ def sub_category_list(category)
+ sub_categories = []
+ category.children.order(:name).each do |sub_category|
+ cat_link = category_link sub_category
+ sub_categories << content_tag('li', cat_link) unless cat_link.nil?
+ end
+ content_tag('ul', sub_categories.join.html_safe) if sub_categories.size > 0
+ end
+
+end
diff --git a/plugins/products/lib/products_plugin/enterprise_homepage_helper.rb b/plugins/products/lib/products_plugin/enterprise_homepage_helper.rb
new file mode 100644
index 0000000..a7f7d62
--- /dev/null
+++ b/plugins/products/lib/products_plugin/enterprise_homepage_helper.rb
@@ -0,0 +1,27 @@
+module ProductsPlugin
+ module EnterpriseHomepageHelper
+
+ def display_profile_info(profile)
+ data = ''
+ [
+ [ _('Contact person:'), :contact_person ],
+ [ _('e-Mail:'), :contact_email ],
+ [ _('Phone(s):'), :contact_phone ],
+ [ _('Location:'), :location ],
+ [ _('Address:'), :address ],
+ [ _('Economic activity:'), :economic_activity ]
+ ].each { | name, att |
+ if profile.send( att ) and not profile.send( att ).blank?
+ data << content_tag( 'li', content_tag('strong', name) +' '+ profile.send( att ).to_s ) +"\n"
+ end
+ }
+ if profile.respond_to?(:distance) and !profile.distance.nil?
+ data << content_tag( 'li',
+ content_tag('strong',_('Distance:')) +' '+
+ "%.2f%" % profile.distance
+ ) + "\n"
+ end
+ content_tag('div', content_tag('ul', data), class: 'enterprise-info')
+ end
+ end
+end
diff --git a/plugins/products/lib/products_plugin/products_helper.rb b/plugins/products/lib/products_plugin/products_helper.rb
new file mode 100644
index 0000000..c7b0920
--- /dev/null
+++ b/plugins/products/lib/products_plugin/products_helper.rb
@@ -0,0 +1,319 @@
+module ProductsPlugin::ProductsHelper
+
+ protected
+
+ def product_path(product)
+ if product.enterprise.enabled?
+ product.enterprise.public_profile_url.merge controller: 'products_plugin/page', action: 'show', id: product
+ else
+ product.enterprise.url
+ end
+ end
+
+ def link_to_product_category(category)
+ if category
+ link_to(category.name, controller: 'search', action: 'products', category_path: category.explode_path)
+ else
+ _('Uncategorized product')
+ end
+ end
+
+ def image_link_to_product(product, opts={})
+ return _('No product') unless product
+ target = product_path(product)
+ link_to image_tag(product.default_image(:big), alt: product.name),
+ target,
+ opts
+ end
+
+ def link_to_product(product, opts={})
+ return _('No product') unless product
+ target = product_path(product)
+ link_to content_tag( 'span', product.name ),
+ target,
+ opts
+ end
+
+ def remote_function_to_update_categories_selection(container_id, options = {})
+ remote_function({
+ update: container_id,
+ url: { action: "categories_for_selection" },
+ loading: "loading('hierarchy_navigation', '#{ _('loading…') }'); loading('#{container_id}', ' ')",
+ complete: "loading_done('hierarchy_navigation'); loading_done('#{container_id}')"
+ }.merge(options))
+ end
+
+ def hierarchy_category_item(category, make_links, title = nil)
+ title ||= category.name
+ if make_links
+ link_to(title, '#',
+ title: title,
+ onclick: remote_function_to_update_categories_selection("categories_container_level#{ category.level + 1 }",
+ with: "'category_id=#{ category.id }'"
+ )
+ )
+ else
+ title
+ end
+ end
+
+ def hierarchy_category_navigation(current_category, options = {})
+ hierarchy = []
+ if current_category
+ hierarchy << current_category.name unless options[:hide_current_category]
+ ancestors = current_category.ancestors
+ ancestors.each do |category|
+ hierarchy << hierarchy_category_item(category, options[:make_links])
+ end
+ end
+ hierarchy.reverse.join(options[:separator] || ' → ')
+ end
+
+ def options_for_select_categories(categories, selected = nil)
+ categories.sort_by{ |cat| cat.name.transliterate}
+ .map do |category|
+ selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '')
+ "#{category.name + (category.leaf? ? '': ' »')} ".html_safe
+ end.safe_join
+ end
+
+ def build_selects_for_ancestors(ancestors, current_category)
+ current_ancestor = ancestors.shift
+ if current_ancestor.nil?
+ select_for_new_category(current_category.children, current_category.level + 1)
+ else
+ content_tag('div',
+ select_tag('category_id',
+ options_for_select_categories(current_ancestor.siblings + [current_ancestor], current_ancestor),
+ size: 10,
+ onchange: remote_function_to_update_categories_selection("categories_container_level#{ current_ancestor.level + 1 }", with: "'category_id=' + this.value")
+ ) +
+ build_selects_for_ancestors(ancestors, current_category),
+ class: 'categories_container',
+ id: "categories_container_level#{ current_ancestor.level }"
+ )
+ end
+ end
+
+ def selects_for_all_ancestors(current_category)
+ build_selects_for_ancestors(current_category.ancestors.reverse + [current_category], current_category)
+ end
+
+ def select_for_new_category(categories, level)
+ content_tag('div',
+ render('products_plugin/page/categories_for_selection', categories: categories, level: level),
+ class: 'categories_container',
+ id: "categories_container_level#{ level }"
+ )
+ end
+
+ def categories_container(categories_selection_html, hierarchy_html = '')
+ content_tag 'div',
+ [render('products_plugin/page/categories_autocomplete') +
+ hidden_field_tag('selected_category_id') +
+ content_tag('div', hierarchy_html, id: 'hierarchy_navigation') +
+ content_tag('div', categories_selection_html, id: 'categories_container_wrapper')].safe_join,
+ id: 'categories-container'
+ end
+
+ def select_for_categories(categories, level = 0)
+ if categories.empty?
+ content_tag('div', '', id: 'no_subcategories')
+ else
+ select_tag('category_id',
+ options_for_select_categories(categories),
+ size: 10,
+ onchange: remote_function_to_update_categories_selection("categories_container_level#{ level + 1 }", with: "'category_id=' + this.value")
+ ) +
+ content_tag('div', '', class: 'categories_container', id: "categories_container_level#{ level + 1 }")
+ end
+ end
+
+ def edit_link(label, url, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ link_to(label, url, html_options)
+ end
+
+ def edit_product_link_to_remote(product, field, label, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ options = html_options.merge(id: 'link-edit-product-' + field)
+ options[:class] = options[:class] ? options[:class] + ' link-to-remote' : 'link-to-remote'
+
+ link_to_remote(label,
+ {update: "product-#{field}",
+ url: { controller: 'products_plugin/page', action: "edit", id: product.id, field: field },
+ method: :get,
+ loading: "loading_for_button('#link-edit-product-#{field}')"},
+ options)
+ end
+
+ def edit_button(type, label, url, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ button(type, label, url, html_options)
+ end
+
+ def edit_product_button_to_remote(product, field, label, html_options = {})
+ the_class = 'button with-text icon-edit'
+ if html_options.has_key?(:class)
+ the_class << ' ' << html_options[:class]
+ end
+ edit_product_link_to_remote(product, field, label, html_options.merge(class: the_class))
+ end
+
+ def edit_ui_button(label, url, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ ui_button(label, url, html_options)
+ end
+
+ def edit_product_ui_button_to_remote(product, field, label, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ id = 'edit-product-remote-button-ui-' + field
+ options = html_options.merge(id: id)
+
+ ui_button_to_remote(label,
+ {update: "product-#{field}",
+ url: { controller: 'products_plugin/page', action: "edit", id: product.id, field: field },
+ complete: "jQuery('#edit-product-button-ui-#{field}').hide()",
+ method: :get,
+ loading: "loading_for_button('##{id}')"},
+ options)
+ end
+
+ def cancel_edit_product_link(product, field, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ button_to_function(:cancel, _('Cancel'), nil, html_options) do |page|
+ page.replace_html "product-#{field}", CGI::escapeHTML(render "products_plugin/page/display_#{field}", product: product)
+ end
+ end
+
+ def edit_product_category_link(product, html_options = {})
+ return '' unless (user && user.has_permission?('manage_products', profile))
+ options = html_options.merge(id: 'link-edit-product-category')
+ link_to(_('Change category'), { action: 'edit_category', id: product.id}, options)
+ end
+
+ def display_value(product)
+ price = product.price
+ return '' if price.blank? || price.zero?
+ discount = product.discount
+ if discount.blank? || discount.zero?
+ result = display_price(_('Price: '), price)
+ else
+ result = display_price_with_discount(price, product.price_with_discount)
+ end
+ content_tag('span', content_tag('span', result, class: 'product-price'), class: "#{product.available? ? '' : 'un'}available-product")
+ end
+
+ def display_availability(product)
+ if !product.available?
+ ui_highlight(_('Product not available!'))
+ end
+ end
+
+ def display_price(label, price)
+ content_tag('span', label, class: 'field-name') +
+ content_tag('span', float_to_currency(price), class: 'field-value')
+ end
+
+ def display_price_with_discount(price, price_with_discount)
+ original_value = content_tag('span', display_price(_('List price: '), price), class: 'list-price')
+ discount_value = content_tag('span', display_price(_('On sale: '), price_with_discount), class: 'on-sale-price')
+ original_value + tag('br') + discount_value
+ end
+
+ def display_qualifiers(product)
+ data = ''
+ product.product_qualifiers.each do |pq|
+ certified_by = ''
+ certifier = pq.certifier
+ if certifier
+ certifier_name = certifier.link.blank? ? certifier.name : link_to(certifier.name, certifier.link)
+ certified_by = _('certified by %s') % certifier_name
+ else
+ certified_by = _('(Self declared)')
+ end
+ data << content_tag('li', "✔ #{pq.qualifier.name} #{certified_by}", class: 'product-qualifiers-item')
+ end
+ content_tag('ul', data, id: 'product-qualifiers')
+ end
+
+ def qualifiers_for_select
+ [[_('Select...'), nil]] + environment.qualifiers.sort.map{ |c| [c.name, c.id] }
+ end
+ def certifiers_for_select(qualifier)
+ [[_('Self declared'), nil]] + qualifier.certifiers.sort.map{ |c| [c.name, c.id] }
+ end
+ def select_qualifiers(product, selected = nil)
+ select_tag('selected_qualifier', options_for_select(qualifiers_for_select, selected),
+ onchange: remote_function(
+ url: {action: 'certifiers_for_selection'},
+ with: "'id=' + value + '&certifier_area=' + jQuery(this).parent().next().attr('id')",
+ before: "small_loading(jQuery(this).parent().next().attr('id'), ' ')"
+ ),
+ id: nil
+ )
+ end
+ def select_certifiers(qualifier, product = nil)
+ if qualifier
+ selected = product ? product.product_qualifiers.find_by(qualifier_id: qualifier.id).certifier_id : nil
+ select_tag("product[qualifiers_list][#{qualifier.id}]", options_for_select(certifiers_for_select(qualifier), selected))
+ else
+ select_tag("product[qualifiers_list][nil]")
+ end
+ end
+
+ def remove_qualifier_button
+ button_to_function(:delete, content_tag('span', _('Delete qualifier')), "jQuery(this).parents('tr').remove()")
+ end
+
+ def select_unit(object)
+ collection_select(object.class.name.downcase, :unit_id, environment.units, :id, :singular, {include_blank: _('Select the unit')})
+ end
+
+ def input_icon(input)
+ if input.is_from_solidarity_economy?
+ hint = _('Product from solidarity economy')
+ image_tag("/images/solidarity-economy.png", class: 'solidatiry-economy-icon', alt: hint, title: hint)
+ end
+ end
+
+ def display_price_by(unit)
+ selected_unit = content_tag('span', unit, class: 'selected-unit')
+ content_tag('span', _('by') + ' ' + selected_unit, class: 'price-by-unit')
+ end
+
+ def label_amount_used(input)
+ product_unit = input.product.unit
+ if product_unit.blank?
+ _('Amount used in this product or service')
+ else
+ _('Amount used by %s of this product or service') % product_unit.singular.downcase
+ end
+ end
+
+ def display_unit(input)
+ input_amount_used = content_tag('span', input.formatted_amount, class: 'input-amount-used')
+ return input_amount_used if input.unit.blank?
+ n_('1 %{singular_unit}', '%{num} %{plural_unit}', input.amount_used.to_f) % { num: input_amount_used, singular_unit: content_tag('span', input.unit.singular, class: 'input-unit'), plural_unit: content_tag('span', input.unit.plural, class: 'input-unit') }
+ end
+
+ def select_production_cost(product,selected=nil)
+ url = url_for( controller: 'products_plugin/page', action: 'create_production_cost' )
+ prompt_msg = _('Insert the name of the new cost:')
+ error_msg = _('Something went wrong. Please, try again')
+ select_tag('price_details[][production_cost_id]',
+ '' + _('Select...') + ' ' +
+ options_for_select(product.available_production_costs.map {|item| [truncate(item.name, {length: 10, omission: '...'}), item.id]} + [[_('Other cost'), '']], selected),
+ {class: 'production-cost-selection',
+ onchange: "productionCostTypeChange(this, '#{url}', '#{prompt_msg}', '#{error_msg}')"})
+ end
+
+ def price_composition_progressbar_text(product, args = {})
+ currency = environment.currency_unit
+ production_cost = args[:production_cost_value] || product.formatted_value(:total_production_cost)
+ product_price = args[:product_price] || product.formatted_value(:price)
+
+ _("%{currency} %{production_cost} of %{currency} %{product_price}") % {currency: currency, production_cost: content_tag('span', production_cost, class: 'production_cost'), product_price: content_tag('span', product_price, class: 'product_price')}
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/certifier.rb b/plugins/products/models/products_plugin/certifier.rb
new file mode 100644
index 0000000..aab72f7
--- /dev/null
+++ b/plugins/products/models/products_plugin/certifier.rb
@@ -0,0 +1,37 @@
+class ProductsPlugin::Certifier < ApplicationRecord
+
+ self.table_name = :certifiers
+
+ attr_accessible :name, :environment
+
+ SEARCHABLE_FIELDS = {
+ :name => {:label => _('Name'), :weight => 10},
+ :description => {:label => _('Description'), :weight => 3},
+ :link => {:label => _('Link'), :weight => 1},
+ }
+
+ belongs_to :environment
+
+ has_many :qualifier_certifiers, :dependent => :destroy
+ has_many :qualifiers, :through => :qualifier_certifiers
+
+ has_many :product_qualifiers
+ has_many :products, :through => :product_qualifiers, :source => :product
+
+ validates_presence_of :environment_id
+ validates_presence_of :name
+
+ def destroy
+ product_qualifiers.each { |pq| pq.update! :certifier => nil }
+ super
+ end
+
+ def link
+ self[:link] || ''
+ end
+
+ def <=>(b)
+ self.name.downcase.transliterate <=> b.name.downcase.transliterate
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/enterprise_homepage.rb b/plugins/products/models/products_plugin/enterprise_homepage.rb
new file mode 100644
index 0000000..c08f325
--- /dev/null
+++ b/plugins/products/models/products_plugin/enterprise_homepage.rb
@@ -0,0 +1,52 @@
+module ProductsPlugin
+
+ class EnterpriseHomepage < Article
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'EnterpriseHomepage'
+ end
+
+ def self.type_name
+ _('Homepage')
+ end
+
+ def self.short_description
+ _('Enterprise homepage')
+ end
+
+ def self.description
+ _('Display the summary of profile.')
+ end
+
+ def name
+ profile.nil? ? _('Homepage') : profile.name
+ end
+
+ def to_html(options = {})
+ enterprise_homepage = self
+ proc do
+ extend EnterpriseHomepageHelper
+ extend CatalogHelper
+ catalog_load_index page: 1, show_categories: false
+ render partial: 'content_viewer/enterprise_homepage', object: enterprise_homepage
+ end
+ end
+
+ # disable cache because of products
+ def cache_key params = {}, the_profile = nil, language = 'en'
+ rand
+ end
+
+ def can_display_hits?
+ false
+ end
+
+ def can_display_media_panel?
+ true
+ end
+
+ end
+end
diff --git a/plugins/products/models/products_plugin/featured_products_block.rb b/plugins/products/models/products_plugin/featured_products_block.rb
new file mode 100644
index 0000000..e97e92f
--- /dev/null
+++ b/plugins/products/models/products_plugin/featured_products_block.rb
@@ -0,0 +1,42 @@
+class ProductsPlugin::FeaturedProductsBlock < Block
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'FeaturedProductsBlock'
+ end
+
+ attr_accessible :product_ids, :groups_of, :speed, :reflect
+
+ settings_items :product_ids, :type => Array, :default => []
+ settings_items :groups_of, :type => :integer, :default => 3
+ settings_items :speed, :type => :integer, :default => 1000
+ settings_items :reflect, :type => :boolean, :default => true
+
+ before_save do |block|
+ if block.owner.kind_of?(Environment) && block.product_ids.blank?
+ total = block.owner.products.count
+ offset = rand([(total - block.groups_of * 3) + 1, 1].max)
+ block.product_ids = block.owner.highlighted_products_with_image.offset(offset).limit(block.groups_of * 3).map(&:id)
+ end
+ block.groups_of = block.groups_of.to_i
+ end
+
+ def self.description
+ _('Featured Products')
+ end
+
+ def self.pretty_name
+ _('Featured Products')
+ end
+
+ def products
+ Product.find(self.product_ids) || []
+ end
+
+ def products_for_selection
+ self.owner.highlighted_products_with_image
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/input.rb b/plugins/products/models/products_plugin/input.rb
new file mode 100644
index 0000000..fac2231
--- /dev/null
+++ b/plugins/products/models/products_plugin/input.rb
@@ -0,0 +1,75 @@
+module ProductsPlugin
+ class Input < ApplicationRecord
+
+ self.table_name = :inputs
+
+ attr_accessible :product, :product_id, :product_category, :product_category_id,
+ :amount_used, :unit_id, :price_per_unit, :relevant_to_price, :is_from_solidarity_economy
+
+ belongs_to :product
+ belongs_to :product_category
+
+ validates_presence_of :product
+ validates_presence_of :product_category
+
+ acts_as_list scope: -> input { where product_id: input.product_id }
+
+ belongs_to :unit
+
+ scope :relevant_to_price, -> { where relevant_to_price: true }
+
+ include FloatHelper
+
+ def price_per_unit=(value)
+ if value.is_a?(String)
+ super(decimal_to_float(value))
+ else
+ super(value)
+ end
+ end
+
+ def amount_used=(value)
+ if value.is_a?(String)
+ super(decimal_to_float(value))
+ else
+ super(value)
+ end
+ end
+
+ def name
+ product_category.name
+ end
+
+ def formatted_value(value)
+ ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value]
+ end
+
+ def formatted_amount
+ amount = self.amount_used
+ return '' if amount.blank? || amount.zero?
+ ("%.2f" % amount).to_s.gsub('.00', '').gsub('.', product.enterprise.environment.currency_separator)
+ end
+
+ def has_price_details?
+ %w[price_per_unit amount_used].each do |field|
+ return true unless self.send(field).blank?
+ end
+ false
+ end
+
+ def has_all_price_details?
+ %w[price_per_unit unit amount_used].each do |field|
+ return false if self.send(field).blank?
+ end
+ true
+ end
+
+ def cost
+ return 0 if self.amount_used.blank? || self.price_per_unit.blank?
+ self.amount_used * self.price_per_unit
+ end
+
+ alias_method :price, :cost
+
+ end
+end
diff --git a/plugins/products/models/products_plugin/price_detail.rb b/plugins/products/models/products_plugin/price_detail.rb
new file mode 100644
index 0000000..8682d36
--- /dev/null
+++ b/plugins/products/models/products_plugin/price_detail.rb
@@ -0,0 +1,36 @@
+class ProductsPlugin::PriceDetail < ApplicationRecord
+
+ self.table_name = :price_details
+
+ attr_accessible :price, :production_cost_id
+ attr_accessible :production_cost
+
+ belongs_to :product
+ validates_presence_of :product_id
+
+ belongs_to :production_cost
+ # Do not validates_presence_of production_cost. We may have undefined other costs.
+ validates_uniqueness_of :production_cost_id, scope: :product_id
+
+ def name
+ production_cost.nil? ? _('Other costs') : production_cost.name
+ end
+
+ def price
+ self[:price] || 0
+ end
+
+ include FloatHelper
+ def price=(value)
+ if value.is_a?(String)
+ super(decimal_to_float(value))
+ else
+ super(value)
+ end
+ end
+
+ def formatted_value(value)
+ ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value]
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/product.rb b/plugins/products/models/products_plugin/product.rb
new file mode 100644
index 0000000..6aecb43
--- /dev/null
+++ b/plugins/products/models/products_plugin/product.rb
@@ -0,0 +1,300 @@
+class ProductsPlugin::Product < ApplicationRecord
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'Product'
+ end
+
+ self.table_name = :products
+
+ SEARCHABLE_FIELDS = {
+ name: {label: _('Name'), weight: 10},
+ description: {label: _('Description'), weight: 1},
+ }
+
+ SEARCH_FILTERS = {
+ order: %w[more_recent],
+ display: %w[full map]
+ }
+
+ attr_accessible :name, :product_category, :profile, :profile_id, :enterprise,
+ :highlighted, :price, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
+
+ def self.default_search_display
+ 'full'
+ end
+
+ belongs_to :profile
+ # backwards compatibility
+ belongs_to :enterprise, foreign_key: :profile_id, class_name: 'Enterprise'
+ alias_method :enterprise=, :profile=
+ alias_method :enterprise, :profile
+
+ has_one :region, through: :profile
+ validates_presence_of :profile
+
+ belongs_to :product_category
+
+ has_many :inputs, -> { order 'position' }, dependent: :destroy
+ has_many :price_details, dependent: :destroy
+ has_many :production_costs, through: :price_details
+
+ has_many :product_qualifiers, dependent: :destroy
+ has_many :qualifiers, through: :product_qualifiers
+ has_many :certifiers, through: :product_qualifiers
+
+ acts_as_having_settings field: :data
+
+ track_actions :create_product, :after_create, keep_params: [:name, :url ], if: Proc.new { |a| a.is_trackable? }, custom_user: :action_tracker_user
+ track_actions :update_product, :before_update, keep_params: [:name, :url], if: Proc.new { |a| a.is_trackable? }, custom_user: :action_tracker_user
+ track_actions :remove_product, :before_destroy, keep_params: [:name], if: Proc.new { |a| a.is_trackable? }, custom_user: :action_tracker_user
+
+ validates_uniqueness_of :name, scope: :profile_id, allow_nil: true, if: :validate_uniqueness_of_column_name?
+
+ validates_presence_of :product_category_id
+ validates_associated :product_category
+
+ validates_numericality_of :price, allow_nil: true
+ validates_numericality_of :discount, allow_nil: true
+
+ scope :more_recent, -> { order 'created_at DESC' }
+
+ scope :from_category, -> category {
+ joins(:product_category).where('categories.path LIKE ?', "%#{category.slug}%") if category
+ }
+
+ scope :visible_for_person, lambda { |person|
+ joins('INNER JOIN "profiles" enterprises ON enterprises."id" = "products"."profile_id"')
+ .joins('LEFT JOIN "role_assignments" ON ("role_assignments"."resource_id" = enterprises."id"
+ AND "role_assignments"."resource_type" = \'Profile\') OR (
+ "role_assignments"."resource_id" = enterprises."environment_id" AND
+ "role_assignments"."resource_type" = \'Environment\' )')
+ .joins('LEFT JOIN "roles" ON "role_assignments"."role_id" = "roles"."id"')
+ .where(
+ ['( (roles.key = ? OR roles.key = ?) AND role_assignments.accessor_type = \'Profile\' AND role_assignments.accessor_id = ? )
+ OR
+ ( ( ( role_assignments.accessor_type = \'Profile\' AND
+ role_assignments.accessor_id = ? ) OR
+ ( enterprises.public_profile = ? AND enterprises.enabled = ? ) ) AND
+ ( enterprises.visible = ? ) )',
+ 'profile_admin', 'environment_administrator', person.id, person.id,
+ true, true, true]
+ ).uniq
+ }
+
+ scope :recent, -> limit=nil { order('id DESC').limit(limit) }
+
+ after_update :save_image
+
+ def lat
+ self.profile.lat
+ end
+ def lng
+ self.profile.lng
+ end
+
+ xss_terminate only: [ :name ], on: 'validation'
+ xss_terminate only: [ :description ], with: 'white_list', on: 'validation'
+
+ belongs_to :unit
+
+ include FloatHelper
+
+ include WhiteListFilter
+ filter_iframes :description
+
+ def iframe_whitelist
+ self.profile && self.profile.environment && self.profile.environment.trusted_sites_for_iframe
+ end
+
+ def name
+ self[:name].blank? ? category_name : self[:name]
+ end
+
+ def name=(value)
+ if (value == category_name)
+ self[:name] = nil
+ else
+ self[:name] = value
+ end
+ end
+
+ def name_is_blank?
+ self[:name].blank?
+ end
+
+ def default_image(size='thumb')
+ image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size
+ end
+
+ acts_as_having_image
+
+ def save_image
+ image.save if image
+ end
+
+ def category_name
+ product_category ? product_category.name : _('Uncategorized product')
+ end
+
+ def url
+ self.profile.public_profile_url.merge(controller: 'products_plugin/page', action: 'show', id: id)
+ end
+
+ def public?
+ self.profile.public?
+ end
+
+ def formatted_value(method)
+ value = self[method] || self.send(method)
+ ("%.2f" % value).to_s.gsub('.', self.profile.environment.currency_separator) if value
+ end
+
+ def price_with_discount
+ discount ? (price - discount) : price
+ end
+
+ def price=(value)
+ if value.is_a?(String)
+ super(decimal_to_float(value))
+ else
+ super(value)
+ end
+ end
+
+ def discount=(value)
+ if value.is_a?(String)
+ super(decimal_to_float(value))
+ else
+ super(value)
+ end
+ end
+
+ def inputs_prices?
+ return false if self.inputs.count <= 0
+ self.inputs.each do |input|
+ return false if input.has_price_details? == false
+ end
+ true
+ end
+
+ def any_inputs_details?
+ return false if self.inputs.count <= 0
+ self.inputs.each do |input|
+ return true if input.has_all_price_details? == true
+ end
+ false
+ end
+
+ def has_basic_info?
+ %w[unit price discount].each do |field|
+ return true if !self.send(field).blank?
+ end
+ false
+ end
+
+ def qualifiers_list=(qualifiers)
+ self.product_qualifiers.destroy_all
+ qualifiers.each do |qualifier_id, certifier_id|
+ if qualifier_id != 'nil'
+ product_qualifier = ProductsPlugin::ProductQualifier.new
+ product_qualifier.product = self
+ product_qualifier.qualifier_id = qualifier_id
+ product_qualifier.certifier_id = certifier_id
+ product_qualifier.save!
+ end
+ end
+ end
+
+ def order_inputs!(order = [])
+ order.each_with_index do |input_id, array_index|
+ input = self.inputs.find(input_id)
+ input.position = array_index + 1
+ input.save!
+ end
+ end
+
+ def name_with_unit
+ unit.blank? ? name : "#{name} - #{unit.name.downcase}"
+ end
+
+ def display_supplier_on_search?
+ true
+ end
+
+ def inputs_cost
+ return 0 if inputs.empty?
+ inputs.relevant_to_price.map(&:cost).inject { |sum,price| sum + price }
+ end
+
+ def total_production_cost
+ return inputs_cost if price_details.empty?
+ inputs_cost + price_details.map(&:price).inject(0){ |sum,price| sum + price }
+ end
+
+ def price_described?
+ return false if price.blank? or price == 0
+ (price - total_production_cost.to_f).zero?
+ end
+
+ def update_price_details(new_price_details)
+ price_details.destroy_all
+ new_price_details.each do |detail|
+ price_details.create(detail)
+ end
+ reload # to remove temporary duplicated price_details
+ price_details
+ end
+
+ def price_description_percentage
+ return 0 if price.blank? || price.zero?
+ total_production_cost * 100 / price
+ end
+
+ def available_production_costs
+ self.profile.environment.production_costs + self.profile.production_costs
+ end
+
+ include Rails.application.routes.url_helpers
+ def price_composition_bar_display_url
+ url_for({host: self.profile.default_hostname, controller: 'products_plugin/page', action: 'display_price_composition_bar', profile: self.profile.identifier, id: self.id }.merge(Noosfero.url_options))
+ end
+
+ def inputs_cost_update_url
+ url_for({host: self.profile.default_hostname, controller: 'products_plugin/page', action: 'display_inputs_cost', profile: self.profile.identifier, id: self.id }.merge(Noosfero.url_options))
+ end
+
+ def percentage_from_solidarity_economy
+ se_i = t_i = 0
+ self.inputs.each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
+ t_i = 1 if t_i == 0 # avoid division by 0
+ p = case (se_i.to_f/t_i)*100
+ when 0 then [0, '']
+ when 0..24.999 then [0, _("0%")];
+ when 25..49.999 then [25, _("25%")];
+ when 50..74.999 then [50, _("50%")];
+ when 75..99.999 then [75, _("75%")];
+ when 100 then [100, _("100%")];
+ end
+ end
+
+ delegate :enabled, :region, :region_id, :environment, :environment_id, to: :profile, allow_nil: true
+
+ protected
+
+ def validate_uniqueness_of_column_name?
+ true
+ end
+
+ def is_trackable?
+ # shopping_cart create products without profile
+ self.profile.present?
+ end
+
+ def action_tracker_user
+ self.profile
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/product_categories_block.rb b/plugins/products/models/products_plugin/product_categories_block.rb
new file mode 100644
index 0000000..c603b31
--- /dev/null
+++ b/plugins/products/models/products_plugin/product_categories_block.rb
@@ -0,0 +1,33 @@
+class ProductsPlugin::ProductCategoriesBlock < Block
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'ProductCategoriesBlock'
+ end
+
+ def self.description
+ _('Product category menu')
+ end
+
+ # the title of the block. Probably will be overriden in subclasses.
+ def default_title
+ _('Catalog')
+ end
+
+ def help
+ _('Helps to filter the products catalog.')
+ end
+
+ DISPLAY_OPTIONS = DISPLAY_OPTIONS.merge('catalog_only' => _('Only on the catalog'))
+
+ def display
+ settings[:display].nil? ? 'catalog_only' : super
+ end
+
+ def display_catalog_only(context)
+ context[:params][:controller] == 'products_plugin/catalog'
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/product_category.rb b/plugins/products/models/products_plugin/product_category.rb
new file mode 100644
index 0000000..e494788
--- /dev/null
+++ b/plugins/products/models/products_plugin/product_category.rb
@@ -0,0 +1,38 @@
+module ProductsPlugin
+ class ProductCategory < ::Category
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'ProductCategory'
+ end
+
+ has_many :products
+ has_many :inputs
+
+ attr_accessible :name, :parent, :environment
+
+ scope :unique, -> { select 'DISTINCT ON (path) categories.*' }
+ scope :by_enterprise, -> enterprise {
+ distinct.joins(:products).
+ where('products.profile_id = ?', enterprise.id)
+ }
+ scope :by_environment, -> environment {
+ where 'environment_id = ?', environment.id
+ }
+
+ def all_products
+ Product.where(product_category_id: (all_children << self).map(&:id))
+ end
+
+ def recent_products(limit = 10)
+ self.products.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit)
+ end
+
+ def self.menu_categories(top_category, env)
+ top_category ? top_category.children : top_level_for(env).select{|c|c.kind_of?(ProductCategory)}
+ end
+
+ end
+end
diff --git a/plugins/products/models/products_plugin/product_qualifier.rb b/plugins/products/models/products_plugin/product_qualifier.rb
new file mode 100644
index 0000000..2e80ea0
--- /dev/null
+++ b/plugins/products/models/products_plugin/product_qualifier.rb
@@ -0,0 +1,11 @@
+class ProductsPlugin::ProductQualifier < ApplicationRecord
+
+ self.table_name = :product_qualifiers
+
+ attr_accessible :qualifier, :product, :certifier
+
+ belongs_to :qualifier
+ belongs_to :product
+ belongs_to :certifier
+
+end
diff --git a/plugins/products/models/products_plugin/production_cost.rb b/plugins/products/models/products_plugin/production_cost.rb
new file mode 100644
index 0000000..c35f623
--- /dev/null
+++ b/plugins/products/models/products_plugin/production_cost.rb
@@ -0,0 +1,13 @@
+class ProductsPlugin::ProductionCost < ApplicationRecord
+
+ self.table_name = :production_costs
+
+ attr_accessible :name, :owner
+
+ belongs_to :owner, :polymorphic => true
+ validates_presence_of :owner
+ validates_presence_of :name
+ validates_length_of :name, :maximum => 30, :allow_blank => true
+ validates_uniqueness_of :name, :scope => [:owner_id, :owner_type]
+
+end
diff --git a/plugins/products/models/products_plugin/products_block.rb b/plugins/products/models/products_plugin/products_block.rb
new file mode 100644
index 0000000..b483ba7
--- /dev/null
+++ b/plugins/products/models/products_plugin/products_block.rb
@@ -0,0 +1,45 @@
+class ProductsPlugin::ProductsBlock < Block
+
+ ##
+ # Keep compatibility with previous core name
+ #
+ def self.sti_name
+ 'ProductsBlock'
+ end
+
+ attr_accessible :product_ids
+
+ include ActionView::Helpers::TagHelper
+ include ActionView::Helpers::UrlHelper
+ include ActionView::Helpers
+ include Rails.application.routes.url_helpers
+
+ def self.description
+ _('Products')
+ end
+
+ def default_title
+ _('Products')
+ end
+
+ def help
+ _('This block presents a list of your products.')
+ end
+
+ settings_items :product_ids, type: Array
+ def product_ids=(array)
+ self.settings[:product_ids] = array
+ if self.settings[:product_ids]
+ self.settings[:product_ids] = self.settings[:product_ids].map(&:to_i)
+ end
+ end
+
+ def products(reload = false)
+ if product_ids.blank?
+ owner.products.order('RANDOM()').limit([4,owner.products.count].min)
+ else
+ owner.products.where(:id => product_ids)
+ end.compact
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/qualifier.rb b/plugins/products/models/products_plugin/qualifier.rb
new file mode 100644
index 0000000..41d69f1
--- /dev/null
+++ b/plugins/products/models/products_plugin/qualifier.rb
@@ -0,0 +1,32 @@
+class ProductsPlugin::Qualifier < ApplicationRecord
+
+ self.table_name = :qualifiers
+
+ attr_accessible :name, :environment
+
+ SEARCHABLE_FIELDS = {
+ :name => {:label => _('Name'), :weight => 1},
+ }
+
+ belongs_to :environment
+
+ has_many :qualifier_certifiers, :dependent => :destroy
+ has_many :certifiers, :through => :qualifier_certifiers
+
+ def used_certs
+ Certifier.joins('INNER JOIN product_qualifiers' +
+ ' ON certifiers.id = product_qualifiers.certifier_id')
+ .where(product_qualifiers: {qualifier_id: self.id})
+ end
+
+ has_many :product_qualifiers, :dependent => :destroy
+ has_many :products, :through => :product_qualifiers, :source => :product
+
+ validates_presence_of :environment_id
+ validates_presence_of :name
+
+ def <=>(b)
+ self.name.downcase.transliterate <=> b.name.downcase.transliterate
+ end
+
+end
diff --git a/plugins/products/models/products_plugin/qualifier_certifier.rb b/plugins/products/models/products_plugin/qualifier_certifier.rb
new file mode 100644
index 0000000..c723b49
--- /dev/null
+++ b/plugins/products/models/products_plugin/qualifier_certifier.rb
@@ -0,0 +1,10 @@
+class ProductsPlugin::QualifierCertifier < ApplicationRecord
+
+ self.table_name = :qualifier_certifiers
+
+ belongs_to :qualifier
+ belongs_to :certifier
+
+ validates_presence_of :qualifier
+
+end
diff --git a/plugins/products/models/products_plugin/unit.rb b/plugins/products/models/products_plugin/unit.rb
new file mode 100644
index 0000000..1eefc19
--- /dev/null
+++ b/plugins/products/models/products_plugin/unit.rb
@@ -0,0 +1,22 @@
+class ProductsPlugin::Unit < ApplicationRecord
+
+ self.table_name = :units
+
+ acts_as_list scope: -> unit { where environment_id: unit.environment_id }
+
+ attr_accessible :name, :singular, :plural, :environment
+
+ belongs_to :environment
+
+ validates_presence_of :environment_id
+ validates_presence_of :singular
+ validates_presence_of :plural
+
+ def name
+ self.singular
+ end
+ def name=(value)
+ self.singular = value
+ end
+
+end
diff --git a/plugins/products/po/pt/products.po b/plugins/products/po/pt/products.po
new file mode 100644
index 0000000..3b0ff55
--- /dev/null
+++ b/plugins/products/po/pt/products.po
@@ -0,0 +1,637 @@
+
+#: app/models/product.rb:128 app/helpers/display_helper.rb:42
+#: app/helpers/display_helper.rb:51
+msgid "Uncategorized product"
+msgstr "Produto não categorizado"
+
+#: app/models/product.rb:268
+msgid "0%"
+msgstr "0%"
+
+#: app/models/product.rb:269
+msgid "25%"
+msgstr "25%"
+
+#: app/models/product.rb:270
+msgid "50%"
+msgstr "50%"
+
+#: app/models/product.rb:271
+msgid "75%"
+msgstr "75%"
+
+#: app/models/product.rb:272
+msgid "100%"
+msgstr "100%"
+
+#: app/models/sellers_search_block.rb:6
+msgid "Search for enterprises and products"
+msgstr "Busca por empreeendimentos e produtos"
+
+#: app/models/sellers_search_block.rb:10
+msgid "Products/Enterprises search"
+msgstr "Busca de Produtos/Serviços"
+
+#: app/models/sellers_search_block.rb:14
+msgid "Search for sellers"
+msgstr "Buscar por vendedores"
+
+#: app/views/search/_full_product.html.erb:13
+msgid "from"
+msgstr "de"
+
+#: app/views/search/_full_product.html.erb:18
+msgid "/"
+msgstr "/"
+
+#: app/views/search/_full_product.html.erb:24
+msgid "Percentage of inputs from solidarity economy"
+msgstr "Porcentagem de insumos da economia solidária"
+
+#: app/views/search/_full_product.html.erb:35
+msgid "Open Price"
+msgstr "Preço aberto"
+
+#: app/views/search/_full_product.html.erb:40
+msgid "Not available"
+msgstr "Indisponível"
+
+#: app/views/search/_full_product.html.erb:47
+msgid "Supplier"
+msgstr "Fornecedor"
+
+#: app/views/search/_full_product.html.erb:65
+msgid "Qualifiers"
+msgstr "Qualificadores"
+
+#: app/views/search/_full_product.html.erb:68
+#: app/views/search/_full_product.html.erb:71
+#: app/views/shared/product/_qualifiers.html.erb:3
+#: app/views/shared/product/_qualifiers.html.erb:6
+msgid ";"
+msgstr ";"
+
+#: app/views/search/_full_product.html.erb:71
+#: app/views/shared/product/_qualifiers.html.erb:6
+msgid "cert. "
+msgstr "cert. "
+
+#: app/views/profile_editor/_organization.html.erb:70
+msgid "Products/Services catalog"
+msgstr "Catálogo de Produtos/Serviços"
+
+#: app/views/profile_editor/_organization.html.erb:71
+msgid "Number of products/services displayed per page on catalog"
+msgstr "Número de produtos/serviços mostrados por página no catálogo"
+
+#: app/views/categories/index.html.erb:10
+msgid "Product Categories"
+msgstr "Categorias de produto"
+
+#: app/views/blocks/product_categories.html.erb:1
+msgid "Catalog start"
+msgstr "Início do catálogo"
+
+#: app/views/blocks/featured_products.html.erb:18
+msgid "See More"
+msgstr "Veja mais"
+
+#: app/views/blocks/featured_products.html.erb:54
+msgid "Please, edit this block and choose some products"
+msgstr "Por favor, edite este bloco e selecione alguns produtos"
+
+#: app/views/manage_products/new.html.erb:1
+#: app/views/manage_products/index.html.erb:28
+msgid "New product or service"
+msgstr "Novo produto ou serviço"
+
+#: app/views/manage_products/new.html.erb:11
+msgid "Select the category of the new product or service"
+msgstr "Selecione a categoria de seu novo produto ou serviço"
+
+#: app/views/manage_products/new.html.erb:16
+#: app/views/manage_products/show.html.erb:72
+msgid "Back to the product listing"
+msgstr "Voltar para lista de produtos"
+
+#: app/views/manage_products/new.html.erb:21
+#: app/views/manage_products/edit_category.html.erb:27
+#: app/views/manage_products/_add_input.html.erb:17
+msgid ""
+"This category does not allow registration of products, select a more "
+"specific category"
+msgstr ""
+"Esta categoria não aceita registro de produtos, selecione uma categoria mais "
+"específica"
+
+#: app/views/manage_products/_display_price_details.html.erb:6
+msgid "Inputs:"
+msgstr "Insumos:"
+
+#: app/views/manage_products/edit_category.html.erb:17
+msgid "Edit category of this product:"
+msgstr "Editar categoria deste produto:"
+
+#: app/views/manage_products/edit_category.html.erb:22
+msgid "Back to product"
+msgstr "Voltar para o produto"
+
+#: app/views/manage_products/_edit_price_details.html.erb:9
+msgid "Are you sure that you want to remove this cost?"
+msgstr "Tem certeza que quer excluir este custo?"
+
+#: app/views/manage_products/_form.html.erb:7
+msgid "Price:"
+msgstr "Preço:"
+
+#: app/views/manage_products/_form.html.erb:9
+msgid "Highlight this product"
+msgstr "Destacar este produto"
+
+#: app/views/manage_products/_form.html.erb:15
+msgid "Create product"
+msgstr "Criar produto"
+
+#: app/views/manage_products/_price_composition_bar.html.erb:20
+msgid ""
+"The production cost of your product is not described yet. If you want to "
+"display the price composition, please add all the costs"
+msgstr ""
+"O custo de produção do seu produto ainda não está descrito. Se desejar "
+"exibir a composição do preço, por favor adicione todos os custos"
+
+#: app/views/manage_products/_price_composition_bar.html.erb:20
+msgid ""
+"The production cost of your product is fully described and will be displayed "
+"on your product's page"
+msgstr ""
+"O custo de produção do seu produto está totalmente descrito e será exibido "
+"na página do seu produto"
+
+#: app/views/manage_products/_price_composition_bar.html.erb:20
+msgid "Congratulations! Now the price is open to the public"
+msgstr "Parabéns! Agora o preço está aberto para o público"
+
+#: app/views/manage_products/_edit_input.html.erb:13
+msgid "Price %s (%s)"
+msgstr "Preço %s (%s)"
+
+#: app/views/manage_products/_edit_input.html.erb:17
+msgid "This input or raw material inpact on the final price of the product?"
+msgstr "Este produto ou matéria-prima inpacta no preço final do produto?"
+
+#: app/views/manage_products/_edit_input.html.erb:26
+msgid "Is it from solidarity economy?"
+msgstr "É da economia solidária?"
+
+#: app/views/manage_products/_edit_input.html.erb:36
+msgid "Save changes of this input or raw material"
+msgstr "Salvar mudanças deste insumo ou matéria-prima"
+
+#: app/views/manage_products/_edit_input.html.erb:37
+msgid "Cancel changes of this input or raw material"
+msgstr "Cancelar mudanças deste insumo ou matéria-prima"
+
+#: app/views/manage_products/_price_details_button.html.erb:2
+msgid "Describe here the cost of production"
+msgstr "Descreva aqui o custo de produção"
+
+#: app/views/manage_products/_price_details_button.html.erb:7
+msgid "Describe details about how the price was defined"
+msgstr "Descreva detalhes sobre como o preço foi definido"
+
+#: app/views/manage_products/edit.html.erb:1
+msgid "Editing"
+msgstr "Editando"
+
+#: app/views/manage_products/_edit_info.html.erb:13
+msgid "Price (%s)"
+msgstr "Preço (%s)"
+
+#: app/views/manage_products/_edit_info.html.erb:17
+msgid "Discount (%s)"
+msgstr "Desconto (%s)"
+
+#: app/views/manage_products/_edit_info.html.erb:18
+msgid "If your product is on sale, fill this field with the discount value"
+msgstr ""
+"Se o seu produto está à venda, preencha este campo com o valor de desconto"
+
+#: app/views/manage_products/_edit_info.html.erb:21
+msgid "Available"
+msgstr "Disponível"
+
+#: app/views/manage_products/_edit_info.html.erb:25
+msgid "Highlight this product?"
+msgstr "Destacar este produto?"
+
+#: app/views/manage_products/_edit_info.html.erb:33
+msgid "Qualifier"
+msgstr "Qualificador"
+
+#: app/views/manage_products/_edit_info.html.erb:34
+msgid "Certifier"
+msgstr "Certificador"
+
+#: app/views/manage_products/_edit_info.html.erb:49
+msgid "Add new qualifier"
+msgstr "Adicionar novo qualificador"
+
+#: app/views/manage_products/_display_info.html.erb:7
+msgid "Edit basic information"
+msgstr "Editar informações básicas"
+
+#: app/views/manage_products/_display_info.html.erb:7
+msgid ""
+"Click here to edit price, discount and qualifiers/certifiers to make your "
+"product more attractive and detailed for the consumers"
+msgstr ""
+"Clique aqui para adicionar preço, desconto e qualificadores/certificadores "
+"para deixar seu produto mais atrativo e detalhado para os consumidores"
+
+#: app/views/manage_products/_display_info.html.erb:9
+msgid "Add price and other basic information"
+msgstr "Adicionar preço e outras informações básicas"
+
+#: app/views/manage_products/_display_info.html.erb:10
+msgid ""
+"Click here to add price, discount and qualifiers/certifiers to make your "
+"product more attractive and detailed for the consumers"
+msgstr ""
+"Clique aqui para adicionar preço, desconto e qualificadores/certificadores "
+"para deixar seu produto mais atrativo e detalhado para os consumidores"
+
+#: app/views/manage_products/_display_name.html.erb:3
+msgid "Edit name and unit"
+msgstr "Editar nome e unidade"
+
+#: app/views/manage_products/_display_name.html.erb:3
+msgid "Click here to edit the name of your product and the unit"
+msgstr "Clique aqui para editar o nome do seu produto e a unidade"
+
+#: app/views/manage_products/show.html.erb:35
+msgid "Inputs and raw material"
+msgstr "Insumos e matéria-prima"
+
+#: app/views/manage_products/show.html.erb:38
+msgid "Price composition"
+msgstr "Composição de preço"
+
+#: app/views/manage_products/show.html.erb:73
+msgid "Remove product or service"
+msgstr "Remover produto ou serviço"
+
+#: app/views/manage_products/_display_inputs.html.erb:6
+msgid "Add the inputs or raw material used by this product"
+msgstr "Adicionar insumos ou matéria-prima utilizados por este produto"
+
+#: app/views/manage_products/_display_inputs.html.erb:11
+msgid ""
+"Add inputs or raw materials used by this product and give more transparency "
+"to consumers about your enterprise"
+msgstr ""
+"Adicione insumos ou matéria-prima usado por este produto e dê mais "
+"transparência aos consumidores sobre seu empreendimento"
+
+#: app/views/manage_products/_display_inputs.html.erb:15
+msgid "Add new input or raw material"
+msgstr "Adicionar novo insumo ou matéria-prima"
+
+#: app/views/manage_products/_display_inputs.html.erb:15
+msgid ""
+"Add new input or raw material used by this product and give more "
+"transparency to consumers about your enterprise"
+msgstr ""
+"Adicione novo insumo ou matéria-prime usado por este produto e dê mais "
+"transparência aos consumidores sobre seu empreendimento"
+
+#: app/views/manage_products/_display_inputs.html.erb:16
+msgid "Drag the input with the mouse to change the order"
+msgstr "Mova o insumo com o mouse para alterar a ordem"
+
+#: app/views/manage_products/_display_inputs.html.erb:25
+msgid "Order inputs"
+msgstr "Ordenar insumos"
+
+#: app/views/manage_products/_add_input.html.erb:8
+msgid "Choose an input or raw material to this product:"
+msgstr "Selecione um insumo ou matéria-prima para este produto:"
+
+#: app/views/manage_products/_manage_product_details.html.erb:9
+msgid "Inputs"
+msgstr "Insumos"
+
+#: app/views/manage_products/_manage_product_details.html.erb:14
+msgid "This value is composed by the total value of registered inputs"
+msgstr "Este valor é composto pelo valor total de insumos registrados"
+
+#: app/views/manage_products/_manage_product_details.html.erb:26
+msgid ""
+"If you leave, you will lose all unsaved information. Are you sure you want "
+"to quit?"
+msgstr ""
+"Se você sair, perderá todas as informações não salvas. Tem certeza que "
+"deseja sair?"
+
+#: app/views/manage_products/_manage_product_details.html.erb:27
+msgid "New cost"
+msgstr "Novo custo"
+
+#: app/views/manage_products/_display_description.html.erb:4
+msgid "Edit description"
+msgstr "Editar descrição"
+
+#: app/views/manage_products/_display_description.html.erb:4
+msgid ""
+"Edit the description of your product and give consumers more information "
+"about what you are advertising"
+msgstr ""
+"Edite a descrição do seu produto e dê aos consumidores mais informações "
+"sobre o que você está anunciando"
+
+#: app/views/manage_products/_display_description.html.erb:9
+msgid "Add some description to your product"
+msgstr "Adicione alguma descrição ao seu produto"
+
+#: app/views/manage_products/_display_description.html.erb:12
+msgid ""
+"Add a description to your product and give consumers more information about "
+"what you are advertising"
+msgstr ""
+"Adicione ao seu produto uma descrição para dar aos consumidores mais "
+"informações sobre o que você está anunciando"
+
+#: app/views/manage_products/_display_input.html.erb:8
+msgid "Are you sure that you want to remove this input or raw material?"
+msgstr "Tem certeza que quer excluir este insumo ou matéria-prima?"
+
+#: app/views/manage_products/_display_input.html.erb:13
+msgid "Click here to add price and the amount used"
+msgstr "Clique aqui para adicionar preço e a quantidade"
+
+#: app/views/manage_products/_categories_autocomplete.html.erb:1
+msgid "type a category for the product"
+msgstr "digite uma categoria para o produto"
+
+#: app/views/manage_products/index.html.erb:1
+msgid "Listing products and services"
+msgstr "Listando produtos e serviços"
+
+#: app/views/manage_products/index.html.erb:6
+msgid "Price"
+msgstr "Preço"
+
+#: app/views/manage_products/index.html.erb:11
+msgid "(no product registered yet)"
+msgstr "(nenhum produto registrado ainda)"
+
+#: app/views/manage_products/index.html.erb:19
+msgid "Are you sure you want to remove this product?"
+msgstr "Tem certeza que quer excluir este produto?"
+
+#: app/views/map_balloon/profile.html.erb:20
+msgid "Products/Services: "
+msgstr "Produtos/Serviços: "
+
+#: app/models/categories_block.rb:6 app/views/manage_products/index.html.erb:5
+msgid "Product"
+msgstr "Produto"
+
+#: app/models/featured_products_block.rb:20
+#: app/views/box_organizer/_featured_products_block.html.erb:1
+msgid "Featured Products"
+msgstr "Produtos em destaque"
+
+#: app/models/profile.rb:72
+msgid "Manage products"
+msgstr "Gerenciar produtos"
+
+#: app/models/product_categories_block.rb:4
+msgid "Product category menu"
+msgstr "Menu de categorias de produto"
+
+#: app/models/product_categories_block.rb:9
+msgid "Catalog"
+msgstr "Catálogo"
+
+#: app/models/product_categories_block.rb:13
+msgid "Helps to filter the products catalog."
+msgstr "Ajuda a filtrar os produtos do catálogo."
+
+#: app/models/product_categories_block.rb:22
+msgid "There are no sub-categories for %s"
+msgstr "Não há subcategorias para %s"
+
+#: app/models/product_categories_block.rb:36
+msgid "Only on the catalog"
+msgstr "Apenas no catálogo"
+
+#: app/models/enterprise.rb:143 app/models/products_block.rb:11
+#: app/models/products_block.rb:15 app/helpers/application_helper.rb:579
+#: app/helpers/assets_helper.rb:9
+#: app/controllers/public/search_controller.rb:52
+msgid "Products"
+msgstr "Produtos"
+
+#: app/models/products_block.rb:19
+msgid "This block presents a list of your products."
+msgstr "Este bloco apresenta a lista de seus produtos."
+
+#: app/models/products_block.rb:39
+msgid "View all products"
+msgstr "Ver todos os produtos"
+
+#: app/helpers/display_helper.rb:4 app/helpers/display_helper.rb:20
+msgid "No product"
+msgstr "Sem produto"
+
+#: app/helpers/categories_helper.rb:5
+msgid "Product Category"
+msgstr "Categoria do Produto"
+
+#: app/helpers/profile_helper.rb:131 app/views/catalog/index.html.erb:11
+#: app/views/blocks/profile_info.html.erb:21
+msgid "Products/Services"
+msgstr "Produtos/Serviços"
+
+#: app/helpers/application_helper.rb:550
+msgid "Principal Product Categories"
+msgstr "Categorias do Produto Principal"
+
+#: app/helpers/manage_products_helper.rb:159
+#: app/views/manage_products/_display_category.html.erb:3
+msgid "Change category"
+msgstr "Alterar categoria"
+
+#: app/helpers/manage_products_helper.rb:167
+msgid "Price: "
+msgstr "Preço: "
+
+#: app/helpers/manage_products_helper.rb:176
+msgid "Product not available!"
+msgstr "Produto não disponível!"
+
+#: app/helpers/manage_products_helper.rb:186
+msgid "List price: "
+msgstr "De: "
+
+#: app/helpers/manage_products_helper.rb:187
+msgid "On sale: "
+msgstr "Por: "
+
+#: app/helpers/manage_products_helper.rb:198
+msgid "certified by %s"
+msgstr "certificado por %s"
+
+#: app/helpers/manage_products_helper.rb:200
+msgid "(Self declared)"
+msgstr "(Auto declarado)"
+
+#: app/helpers/manage_products_helper.rb:208
+#: app/helpers/manage_products_helper.rb:272
+msgid "Select..."
+msgstr "Selecione..."
+
+#: app/helpers/manage_products_helper.rb:211
+msgid "Self declared"
+msgstr "Auto declarado"
+
+#: app/helpers/manage_products_helper.rb:233
+msgid "Delete qualifier"
+msgstr "Remover qualificador"
+
+#: app/helpers/manage_products_helper.rb:237
+msgid "Select the unit"
+msgstr "Selecione a unidade"
+
+#: app/helpers/manage_products_helper.rb:242
+msgid "Product from solidarity economy"
+msgstr "Produto da economia solidária"
+
+#: app/helpers/manage_products_helper.rb:255
+msgid "Amount used in this product or service"
+msgstr "Quantidade utilizada neste produto ou serviço"
+
+#: app/helpers/manage_products_helper.rb:257
+msgid "Amount used by %s of this product or service"
+msgstr "Quantidade utilizada por %s deste produto ou serviço"
+
+#: app/helpers/manage_products_helper.rb:264
+msgid "1 %{singular_unit}"
+msgid_plural "%{num} %{plural_unit}"
+msgstr[0] "1 %{singular_unit}"
+msgstr[1] "%{num} %{plural_unit}"
+
+#: app/helpers/manage_products_helper.rb:269
+msgid "Insert the name of the new cost:"
+msgstr "Insira o nome do novo custo:"
+
+#: app/helpers/manage_products_helper.rb:270
+msgid "Something went wrong. Please, try again"
+msgstr "Algo deu errado. Por favor, tente novamente"
+
+#: app/helpers/manage_products_helper.rb:273
+msgid "Other cost"
+msgstr "Outro custo"
+
+#: app/helpers/manage_products_helper.rb:283
+msgid "%{currency} %{production_cost} of %{currency} %{product_price}"
+msgstr "%{currency} %{production_cost} de %{currency} %{product_price}"
+
+#: app/helpers/action_tracker_helper.rb:71
+msgid "created the product %{title}"
+msgstr "criou o produto %{title}"
+
+#: app/helpers/action_tracker_helper.rb:77
+msgid "updated the product %{title}"
+msgstr "atualizou o produto %{title}"
+
+#: app/helpers/action_tracker_helper.rb:83
+msgid "removed the product %{title}"
+msgstr "removeu o produto %{title}"
+
+#: app/controllers/public/search_controller.rb:185
+#: app/controllers/public/search_controller.rb:260
+msgid "Products and Services"
+msgstr "Produtos e Serviços"
+
+#: app/controllers/my_profile/manage_products_controller.rb:58
+msgid "Product succesfully created"
+msgstr "Produto criado com sucesso"
+
+#: app/controllers/my_profile/manage_products_controller.rb:162
+msgid "Product succesfully removed"
+msgstr "Produto removido com sucesso"
+
+#: app/controllers/my_profile/manage_products_controller.rb:165
+msgid "Could not remove the product"
+msgstr "Não foi possível remover o produto"
+
+#: app/controllers/my_profile/manage_products_controller.rb:184
+msgid "The input was not found"
+msgstr "O insumo não foi encontrado"
+
+#: app/views/catalog/index.html.erb:28
+msgid "Highlighted product"
+msgstr "Produto destacado"
+
+#: app/views/catalog/index.html.erb:119
+msgid "product unavailable"
+msgstr "produto indisponível"
+
+#: app/views/catalog/index.html.erb:46
+msgid "from "
+msgstr "de "
+
+#: app/views/catalog/index.html.erb:47
+msgid "by "
+msgstr "por "
+
+#: app/views/catalog/index.html.erb:53
+msgid " / "
+msgstr " / "
+
+#: app/views/catalog/index.html.erb:53
+msgid "unit"
+msgstr "unidade"
+
+#: app/views/catalog/index.html.erb:71
+msgid "price composition"
+msgstr "composição de preço"
+
+#: app/views/catalog/index.html.erb:94
+msgid "inputs and raw materials"
+msgstr "Insumos e matéria-prima"
+
+#: app/views/catalog/index.html.erb:100
+msgid "%{amount_used} %{unit} of"
+msgstr "%{amount_used} %{unit} de"
+
+#: app/views/catalog/index.html.erb:111
+msgid "qualifiers"
+msgstr "qualificadores"
+
+#: app/views/box_organizer/_products_block.html.erb:5
+msgid "Select the products that must be shown."
+msgstr "Escolha os produtos que serão exibidos."
+
+#: app/views/box_organizer/_featured_products_block.html.erb:3
+msgid "Choose some products"
+msgstr "Selecione alguns produtos"
+
+#: app/views/box_organizer/_featured_products_block.html.erb:5
+msgid "Reflect products"
+msgstr "Refletir produtos"
+
+#: app/views/box_organizer/_featured_products_block.html.erb:6
+msgid "Transition speed (in seconds)"
+msgstr "Velocidade da transição (em segundos)"
+
+#: app/views/box_organizer/_featured_products_block.html.erb:7
+msgid "In groups of"
+msgstr "Em grupos de"
+
+#: app/helpers/catalog_helper.rb:18
+msgid "Start"
+msgstr "Início"
+
diff --git a/plugins/products/public/images/catalog-expanders.png b/plugins/products/public/images/catalog-expanders.png
new file mode 100644
index 0000000..395e0b2
Binary files /dev/null and b/plugins/products/public/images/catalog-expanders.png differ
diff --git a/plugins/products/public/javascripts/catalog.js b/plugins/products/public/javascripts/catalog.js
new file mode 100644
index 0000000..79e56e2
--- /dev/null
+++ b/plugins/products/public/javascripts/catalog.js
@@ -0,0 +1,29 @@
+(function($) {
+
+ function toggle_expandbox(element, open) {
+ element.clicked = open;
+ $(element).toggleClass('open', open);
+ }
+
+ $('#product-list .expand-box').live('click', function () {
+ var me = this;
+ $('.expand-box').each(function(index, element){
+ if ( element != me ) toggle_expandbox(element, false);
+ });
+ toggle_expandbox(me, !me.clicked);
+ return false;
+ });
+
+ $('#product-list .float-box').live('click', function () {
+ return false;
+ });
+
+ $(document).click(function (event) {
+ if ($(event.target).parents('.expand-box').length == 0) {
+ $('#product-list .expand-box').each(function(index, element){
+ toggle_expandbox(element, false);
+ });
+ }
+ });
+
+})(jQuery);
diff --git a/plugins/products/public/javascripts/manage-products.js b/plugins/products/public/javascripts/manage-products.js
new file mode 100644
index 0000000..919af6b
--- /dev/null
+++ b/plugins/products/public/javascripts/manage-products.js
@@ -0,0 +1,194 @@
+(function($) {
+
+ $("#manage-product-details-button").live('click', function() {
+ $("#product-price-details").find('.loading-area').addClass('small-loading');
+ url = $(this).attr('href');
+ $.get(url, function(data){
+ $("#manage-product-details-button").hide();
+ $("#display-price-details").hide();
+ $("#display-manage-price-details").html(data);
+ $("#product-price-details").find('.loading-area').removeClass('small-loading');
+ });
+ return false;
+ });
+
+ $(".cancel-price-details").live('click', function() {
+ if ( !$(this).hasClass('form-changed') ) {
+ cancelPriceDetailsEdition();
+ } else {
+ if (confirm($(this).attr('data-confirm'))) {
+ cancelPriceDetailsEdition();
+ }
+ }
+ return false;
+ });
+
+ $('#manage-product-details-form').live('submit', function(data) {
+ var form = this;
+ $(form).find('.loading-area').addClass('small-loading');
+ $(form).css('cursor', 'progress');
+ var request = $.ajax(form.action, {
+ type: 'POST',
+ dataType: 'html',
+ data: $(form).serialize()
+ });
+ request.done(function(data, textStatus, jqXHR) {
+ $('#display-manage-price-details').html(data);
+ $('#manage-product-details-button').show();
+ });
+ request.fail(function(jqXHR, textStatus, errorThrown) {
+ log.error('manage_product_details', 'Request failed', errorThrown);
+ alert('manage_product_details\nRequest failed: '+ errorThrown +
+ '\n\nPlease, contact the site administrator.');
+ $('#display-manage-price-details .loading-area').hide();
+ });
+ if ($('#progressbar-icon').hasClass('ui-icon-check')) {
+ display_notice($('#progressbar-icon').attr('data-price-described-notice'));
+ }
+ return false;
+ });
+
+ $("#add-new-cost").live('click', function() {
+ $('#display-product-price-details tbody').append($('#new-cost-fields tbody').html());
+ return false;
+ });
+
+ $(".cancel-new-cost").live('click', function() {
+ $(this).parents('tr').remove();
+ calculateValuesForBar();
+ return false;
+ });
+
+ $("#product-info-form").live('submit', function(data) {
+ var form = this;
+ updatePriceCompositionBar(form);
+ });
+
+ $("form.edit_input").live('submit', function(data) {
+ var form = this;
+ inputs_cost_update_url = $(form).find('#inputs-cost-update-url').val();
+ $.get(inputs_cost_update_url, function(data){
+ $(".inputs-cost span").html(data);
+ });
+ updatePriceCompositionBar(form);
+ return false;
+ });
+
+ $("#manage-product-details-form .price-details-price").live('blur', function(data) { calculateValuesForBar(); });
+
+ function cancelPriceDetailsEdition() {
+ $("#manage-product-details-button").show();
+ $("#display-price-details").show();
+ $("#display-manage-price-details").html('');
+ };
+
+})(jQuery);
+
+function updatePriceCompositionBar(form) {
+ bar_url = jQuery(form).find('.bar-update-url').val();
+ jQuery.ajax({
+ url : bar_url,
+ success : function(data) {
+ jQuery("#price-composition-bar").html(data);
+ },
+ complete : function() {
+ jQuery('form #product_price').val(currencyToFloat(jQuery('#progressbar-text .product_price').html(), currency_format.separator, currency_format.delimiter));
+ jQuery('form #product_inputs_cost').val(currencyToFloat(jQuery('#display-product-price-details .inputs-cost span').html(), currency_format.separator, currency_format.delimiter, currency_format.unit));
+ calculateValuesForBar();
+ }
+ });
+};
+
+function enablePriceDetailSubmit() {
+ jQuery('#manage-product-details-form input.submit').removeAttr("disabled").removeClass('disabled');
+}
+
+function calculateValuesForBar() {
+ jQuery('.cancel-price-details').addClass('form-changed');
+ var product_price = parseFloat(jQuery('form #product_price').val());
+ var total_cost = parseFloat(jQuery('form #product_inputs_cost').val());
+
+ jQuery('form .price-details-price').each(function() {
+ var this_val = parseFloat(jQuery(this).val().replace(currency_format.separator, '.')) || 0;
+ total_cost = total_cost + this_val;
+ });
+ enablePriceDetailSubmit();
+
+ var described = (product_price - total_cost) == 0;
+ var percentage = total_cost * 100 / product_price;
+ priceCompositionBar(percentage, described, total_cost, product_price);
+}
+
+function addCommas(nStr) {
+ nStr += '';
+ var x = nStr.split('.');
+ var x1 = x[0];
+ var x2 = x.length > 1 ? '.' + x[1] : '';
+ var rgx = /(\d+)(\d{3})/;
+ while (rgx.test(x1)) {
+ x1 = x1.replace(rgx, '$1' + ',' + '$2');
+ }
+ return x1 + x2;
+}
+
+function floatToCurrency(value, sep, del, cur) {
+ var ret = '';
+ if (cur) ret = cur + ' ';
+ if (!sep) sep = '.';
+ if (!del) del = ',';
+ return ret + addCommas(parseFloat(value).toFixed(2).toString()).replace('.', '%sep%').replace(',', del).replace('%sep%', sep);
+}
+
+function currencyToFloat(value, sep, del, cur) {
+ var val = value;
+ if (cur) val = val.replace(cur + ' ', '');
+ if (!sep) sep = '.';
+ if (!del) del = ',';
+ return parseFloat(val.replace(del, '').replace(sep, '.'));
+}
+
+function productionCostTypeChange(select, url, question, error_msg) {
+ if (select.value == '') {
+ var newType = prompt(question);
+ if (newType) {
+ jQuery.ajax({
+ url: url + "/" + newType,
+ dataType: 'json',
+ success: function(data, status, ajax){
+ if (data.ok) {
+ var opt = jQuery('' + newType + ' ');
+ opt.insertBefore(jQuery("option:last", select));
+ select.selectedIndex = select.options.length - 2;
+ opt.clone().insertBefore('#new-cost-fields .production-cost-selection option:last');
+ } else {
+ alert(data.error_msg);
+ }
+ },
+ error: function(ajax, status, error){
+ alert(error_msg);
+ }
+ });
+ }
+ }
+}
+
+function priceCompositionBar(value, described, total_cost, price) {
+ jQuery(function($) {
+ var bar_area = $('#price-composition-bar');
+ $(bar_area).find('#progressbar').progressbar({
+ value: value
+ });
+ $(bar_area).find('.production_cost').html(floatToCurrency(total_cost, currency_format.separator, currency_format.delimiter));
+ $(bar_area).find('.product_price').html(floatToCurrency(price, currency_format.separator, currency_format.delimiter));
+ if (described) {
+ $(bar_area).find('#progressbar-icon').addClass('ui-icon-check');
+ $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-described-message'));
+ $(bar_area).find('div.ui-progressbar-value').addClass('price-described');
+ } else {
+ $(bar_area).find('#progressbar-icon').removeClass('ui-icon-check');
+ $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-not-described-message'));
+ $(bar_area).find('div.ui-progressbar-value').removeClass('price-described');
+
+ }
+ });
+}
diff --git a/plugins/products/public/javascripts/product_categories.js b/plugins/products/public/javascripts/product_categories.js
new file mode 100644
index 0000000..409b753
--- /dev/null
+++ b/plugins/products/public/javascripts/product_categories.js
@@ -0,0 +1,40 @@
+product_categories = {
+
+ autocomplete: {
+ search_url: '',
+ select_url: '',
+
+ load: function(elem) {
+ elem = jQuery(elem)
+
+ elem.autocomplete({
+ minLength: 3,
+ selectFirst: true,
+
+ //define callback to retrieve results
+ source: function(req, add) {
+ //pass request to server
+ //The alt attribute contains the wordpress callback action
+ var params = { term: req.term };
+ jQuery.getJSON(product_categories.autocomplete.search_url, params, function(data) {
+ add(data);
+ });
+ },
+
+ focus: function( event, ui ) {
+ jQuery(this).val(ui.item.label);
+ return false;
+ },
+
+ select: function(e, ui) {
+ jQuery('#categories-container').load(product_categories.autocomplete.select_url, {category_id: ui.item.value})
+
+ jQuery(this).val("")
+ },
+
+ });
+
+ },
+ },
+
+};
diff --git a/plugins/products/public/javascripts/products.js b/plugins/products/public/javascripts/products.js
new file mode 100644
index 0000000..9fd2328
--- /dev/null
+++ b/plugins/products/public/javascripts/products.js
@@ -0,0 +1,7 @@
+//= require manage-products
+//= require catalog
+//= require product_categories
+
+products = {
+
+}
diff --git a/plugins/products/public/style.scss b/plugins/products/public/style.scss
new file mode 120000
index 0000000..49c35bf
--- /dev/null
+++ b/plugins/products/public/style.scss
@@ -0,0 +1 @@
+stylesheets/style.scss
\ No newline at end of file
diff --git a/plugins/products/public/stylesheets/blocks/featured-products.scss b/plugins/products/public/stylesheets/blocks/featured-products.scss
new file mode 100644
index 0000000..7d3e2b8
--- /dev/null
+++ b/plugins/products/public/stylesheets/blocks/featured-products.scss
@@ -0,0 +1,84 @@
+
+.featured-product-items {
+ width: 100%;
+ display: table;
+ margin: 0 auto;
+ text-align: center;
+}
+.featured-product-items ul {
+ display: table-row;
+}
+.featured-product-item {
+ list-style-type: none;
+ display: table-cell !important;
+}
+.featured-product-item div {
+ margin: 0 auto;
+}
+.featured-products-list {
+ padding: 0;
+}
+.featured-product-arrow {
+ float: left;
+ width: 20px;
+ background-repeat: no-repeat;
+ height: 160px;
+ background-position: center 55px;
+}
+.featured-product-arrow span {
+ display: none;
+}
+.featured-product-prev {
+ background-image: url(../designs/icons/tango/Tango/16x16/actions/go-previous.png);
+}
+.featured-product-next {
+ background-image: url(../designs/icons/tango/Tango/16x16/actions/go-next.png);
+}
+.featured-products-block-container {
+ width: 92%;
+}
+.box-2 .featured-products-block-container, .box-3 .featured-products-block-container {
+ width: 78%;
+}
+.featured-products-group {
+ width: 100%;
+ margin: 0 auto;
+ text-align: center;
+}
+.featured-product-desc {
+ display: none;
+}
+.featured-products-block-container, .featured-products-group {
+ overflow: hidden;
+ float: left;
+ height: 160px;
+ position: relative;
+}
+.featured-products-group ul {
+ padding: 0;
+ padding-left: 4px;
+}
+.featured-products-footer {
+ clear: both;
+}
+.featured-product-info {
+ position: absolute;
+ top: 0;
+ z-index: 9999;
+ height: 125px;
+ overflow: hidden;
+ font-size: 11px;
+ background-color: #fff;
+ opacity: 0.7;
+ border: 1px solid #333;
+ padding: 5px;
+ text-align: left;
+}
+.box-2 .featured-product-info, .box-3 .featured-product-info {
+ width: 110px;
+ margin-left: 50%;
+ left: -60px;
+}
+#content .featured-product-info h3 {
+ font-size: 11px;
+}
diff --git a/plugins/products/public/stylesheets/blocks/products.scss b/plugins/products/public/stylesheets/blocks/products.scss
new file mode 100644
index 0000000..7640c05
--- /dev/null
+++ b/plugins/products/public/stylesheets/blocks/products.scss
@@ -0,0 +1,32 @@
+
+.products-block ul {
+ margin: 0px;
+ padding: 0px 5px 0px 0px;
+ display: table;
+ border-spacing: 5px;
+}
+#content .products-block li {
+ margin: 0px;
+ padding: 0px;
+ list-style: none;
+ list-style-image: none;
+ font-size: 12px;
+ height: 64px;
+ display: table-row;
+}
+#content .products-block li a {
+ background-repeat: no-repeat;
+ background-position: 5px 50%;
+ display: table-cell;
+ vertical-align: middle;
+ padding: 5px 2px 5px 60px;
+ height: 50px;
+ overflow: hidden;
+ text-decoration: none;
+}
+.msie #content .products-block li a {
+ display: block;
+}
+#content .products-block li a:hover {
+ color: #fff;
+}
diff --git a/plugins/products/public/stylesheets/catalog.scss b/plugins/products/public/stylesheets/catalog.scss
new file mode 100644
index 0000000..e3bc6e1
--- /dev/null
+++ b/plugins/products/public/stylesheets/catalog.scss
@@ -0,0 +1,247 @@
+
+#product-catalog {
+ text-align: center;
+}
+
+.product-catalog-ctrl {
+ float: right;
+}
+
+#product-list {
+ display: inline-block;
+ text-align: left;
+ line-height: 20px;
+ margin: 0px;
+ padding: 0px;
+ list-style: none;
+}
+#product-list ul {
+ margin: 0px;
+ padding: 0px;
+ list-style: none;
+}
+#product-list li.product {
+ display: inline-block;
+ width: 200px;
+ min-height: 280px;
+ padding: 10px 15px;
+ margin-bottom: 10px;
+ vertical-align: top;
+}
+#product-list .expand-box:hover {
+ background-color: #28F091;
+}
+#product-list .expand-box {
+ background-color: #1EB46D;
+ margin-bottom: 3px;
+ -moz-border-radius: 10px 0px 0px 10px;
+ -webkit-border-radius: 10px 0px 0px 10px;
+ border-radius: 10px 0px 0px 10px;
+ position: relative;
+}
+#product-list .expand-box > span {
+ padding-left: 20px;
+ font-size: 0.70em;
+ color: white;
+ font-weight: bold;
+ background: url(/plugins/products/images/catalog-expanders.png) no-repeat;
+ display: block;
+ line-height: 15px;
+ background-position: left 100%;
+ cursor: pointer;
+}
+#product-list .expand-box.open > span {
+ background-position: left top;
+}
+#product-list .expand-box-corner {
+}
+#product-list li.product .product-qualifiers {
+ font-size: 9px;
+ line-height: normal;
+}
+#product-list li.product .product-qualifiers > span {
+ font-weight: bold;
+ display: block;
+ margin-top: 8px;
+}
+#product-list li.product .product-qualifiers > span,
+#product-list li.product .expand-box > span {
+ text-transform: uppercase;
+}
+#product-list li.product .expand-box .float-box {
+ display: none;
+ position: absolute;
+ left: -220px;
+ top: -11px;
+ z-index: 10;
+}
+#product-list li.product .expand-box.open .float-box {
+ display: block;
+}
+#product-list li.product .expand-box .content {
+ font-size: 11px;
+ padding: 6px 5px;
+ overflow: auto;
+ max-height: 200px;
+ width: 200px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ background: #DCFFD7;
+ border: 2px solid #1EB46D;
+ min-height: 30px;
+ float: left;
+ text-align: left;
+}
+#product-list li.product .expand-box .arrow {
+ border-left: 6px solid #1EB46D;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ margin-top: 13px;
+ float: right;
+}
+
+#product-list li.product.not-available .expand-box {
+ background-color: #DCF3E9;
+}
+#product-list li.product.not-available .product-link a,
+#product-list li.product.not-available .product-qualifiers,
+#product-list li.product.not-available .product-price-line,
+#product-list li.product.not-available .product-price,
+#product-list li.product.not-available .product-unit {
+ color: #ACACAC !important;
+}
+#product-list .product-link {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ color: #006672;
+ font-weight: bold;
+ text-align: left;
+}
+#product-list .prop {
+ float:right;
+ width:1px;
+}
+#product-list .min50px {
+ height:50px;
+}
+#product-list .product-row-clear {
+ clear:both;
+ height:1px;
+ overflow:hidden;
+}
+
+#product-list .product-price-line {
+ margin: 0 0 8px;
+ display: block;
+ clear: both;
+}
+#product-list .product-price {
+ font-weight: bold;
+}
+#product-list .product-price,
+#product-list .product-unit {
+ color: #0194C7;
+}
+#product-list .product-unit,
+#product-list .product-discount,
+#product-list .product-discount-by {
+ font-size: 9px;
+ margin-right: 3px;
+}
+#product-list .product-discount,
+#product-list .product-price {
+ float: left;
+ line-height: 15px;
+ margin-right: 3px;
+}
+#product-list .product-discount span {
+ text-decoration: line-through;
+}
+#product-list .product-discount-by {
+ text-decoration: none !important;
+}
+
+#product-list .search-product-input-dots-to-price {
+ width: 100%;
+ margin: 0;
+}
+#product-list .search-product-input-name {
+ background-color: #DCFFD7;
+ max-width: 101px;
+}
+#product-list .search-product-input-price {
+ background-color: #DCFFD7;
+}
+
+#product-list .catalog-item-extras {
+ position: absolute;
+ bottom: 0px;
+ right: 0px;
+}
+#product-list .product-big {
+ background-repeat: no-repeat;
+ background-position: 50% 50%;
+ display: block;
+ height: 160px;
+}
+#product-list .ui-button {
+ margin: 0;
+}
+#product-list .ui-button-text {
+ color: #D38D5F;
+ font-size: 0.8em;
+ padding: 0.1em 0.3em 0.1em 3em;
+}
+#product-list .product-big span {
+ display: none;
+}
+#product-list .product-image-link {
+ position: relative;
+ height: 160px;
+ border: 1px solid #BFBFBF;
+ position: relative; /* work arround msie bug */
+ text-align: center;
+ vertical-align: middle;
+}
+#product-list .product-image-link .no-image {
+ line-height: 145px;
+ text-align: center;
+ color: #777;
+ font-size: 9px;
+ font-weight: bold;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ user-select: none;
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+}
+#product-list li.product-unavailable {
+ text-transform: uppercase;
+ color: #FF6261;
+ font-weight: bold;
+ line-height: 40px;
+}
+#product-list h3 {
+ margin: 0px;
+ padding: 0px;
+ font-size: 120%;
+}
+.msie #product-list h3 {
+ margin-top: -15px;
+}
+
+#product-list .highlighted img.star {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ z-index: 1;
+}
+
+#breadcrumb {
+ font-size: 16px;
+ margin: 15px 0;
+ text-align: left;
+}
+
diff --git a/plugins/products/public/stylesheets/product-category.scss b/plugins/products/public/stylesheets/product-category.scss
new file mode 100644
index 0000000..3c9c052
--- /dev/null
+++ b/plugins/products/public/stylesheets/product-category.scss
@@ -0,0 +1,90 @@
+
+/* * * icons for product category on profile * * */
+
+#content .product-category-icons {
+ position: absolute;
+ top: 1px;
+ right: 1px;
+}
+#content .profile-list-block .product-category-icons, #content .search-results-innerbox .product-category-icons {
+ top: 3px;
+ right: 3px;
+}
+#content .product-category-icons .header, #content .product-cat-icon span {
+ display: none;
+}
+#content .product-cat-icon {
+ display: block;
+ width: 13px;
+ height: 13px;
+ margin-bottom: 1px;
+}
+/* * * category ajax selector * * */
+#category-ajax-selector .category-helper-label {
+ font-size: 16px;
+ color: rgb(158, 158, 158);
+ padding: 5px 0px;
+}
+#category-ajax-selector {
+ border: 1px solid #AAA;
+ padding: 3px 10px 10px 10px;
+ margin: 0px 0px 0px 0px;
+ position: relative;
+ font-size: 10px;
+ background-color: #fcfcf9;
+}
+#category-ajax-selector a {
+ font-size: 12px;
+}
+#selected-categories {
+ padding-bottom: 5px;
+}
+#selected-categories .label {
+ font-size: 16px;
+ margin-bottom: 10px;
+ margin-top: 5px;
+}
+.selected-category {
+ padding: 2px 0;
+}
+#category-ajax-selector .box-title {
+ position: absolute;
+ top: -30px;
+ left: 30px;
+ line-height: 19px;
+ padding: 0px 10px;
+ border: 1px solid #AAA;
+ border-bottom: none;
+ background: #EEE;
+ float: left;
+}
+.msie6 #category-ajax-selector .box-title {
+ top: -29px;
+}
+#category-ajax-selector .select-subcategory-link,
+.select-subcategory-link {
+ border: 1px solid #BBB;
+ padding: 1px 3px;
+ margin: 0px 1px;
+ text-decoration: none;
+ white-space: nowrap;
+ font-size: 12px;
+ line-height: 20px;
+ border-radius: 3px;
+}
+#category-ajax-selector .selected-category .select-subcategory-link {
+ border: 0;
+}
+#category-ajax-selector .select-subcategory-link:hover,
+.select-subcategory-link:hover {
+ background-color: black;
+}
+#category-ajax-selector .button {
+ top: 4px;
+ right: 2px;
+}
+#category-ajax-selector hr {
+ border: 0;
+ border-bottom: 1px solid #EEE;
+ margin-top: 15px;
+}
diff --git a/plugins/products/public/stylesheets/product.scss b/plugins/products/public/stylesheets/product.scss
new file mode 100644
index 0000000..736fa7f
--- /dev/null
+++ b/plugins/products/public/stylesheets/product.scss
@@ -0,0 +1,231 @@
+@import 'product/inputs';
+@import 'product/categories-selection';
+
+.link-to-remote {
+ position: relative;
+}
+.product-search-filter {
+}
+
+.controller-catalog #show_product .product-pic {
+ border: 1px solid #D3D7CF;
+}
+#show_product, #category-product-edition {
+ background-color: transparent;
+ position: relative;
+ padding: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+#show_product h2, #category-product-edition h2 {
+ margin-top: 0px;
+}
+#product-category, .product-category-hierarchy {
+ margin-top: 40px;
+ margin-bottom: 12px;
+ padding-left: 7px;
+}
+#product-category {
+ height: 18px;
+}
+#product-category p {
+ display: inline;
+}
+#category-product-edition {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+#display-product-name, #display-product-category {
+ float: left;
+}
+#product-details {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ position: relative;
+}
+#edit-product-name {
+ margin-top: 10px;
+}
+#product-name, #product-details {
+ position: relative;
+ clear: left;
+}
+#product-details, #product-info, .input-item {
+ overflow: hidden;
+}
+#product-info {
+ width: 335px;
+ text-align: left;
+ min-height: 150px;
+ padding-bottom: 5px;
+}
+#display-product-info .field-value {
+ font-weight: bold;
+}
+#edit-product-category {
+ padding: 15px 5px 10px;
+}
+#product-info .field-name {
+ margin-top: 5px;
+ margin-bottom: 15px;
+}
+.edit_product #product_price, .edit_product #product_discount {
+ width: 110px;
+}
+#product_unit {
+ width: 100px;
+}
+#product-info .section-title {
+ display: none;
+}
+#product-qualifiers {
+ padding-left: 0px;
+}
+#product-qualifiers li {
+ list-style: none;
+}
+#product-image {
+ text-align: center;
+ padding: 10px;
+ width: 250px;
+ margin-right: 10px;
+ margin-bottom: 5px;
+ float: left;
+ border: 1px solid #AAA;
+}
+#product-image p {
+ font-size: 11px;
+ font-style: italic;
+ margin-top: 0px;
+ color: #555;
+}
+#display-product-image {
+ margin-bottom: 10px;
+ overflow: hidden;
+}
+#edit-product-image {
+ position: relative;
+ margin-top: 5px;
+}
+#product-qualifiers-list {
+ padding: 0px;
+ margin-bottom: 10px;
+}
+#product-qualifiers-list li {
+ list-style: none;
+}
+#product-qualifiers-list .product-qualifier-title, #product-qualifiers-list .product-certifier-title {
+ margin-right: 20px;
+}
+#edit-product-button-ui-inputs {
+ margin-top: 20px;
+}
+#new-product-input h3 {
+ margin-top: 0px;
+}
+.input-image .ui-icon, #display-add-input-button .hint {
+ display: none;
+}
+#product-qualifiers-list .icon-delete {
+ margin-left: 10px;
+}
+#product-qualifiers-list .icon-add {
+ margin-top: 5px;
+}
+#display-product-info .unavailable-product .product-price {
+ text-decoration: line-through;
+ color: #555;
+}
+#display-product-info .alert {
+ font-weight: bold;
+ color: #D33;
+ margin-top: 10px;
+}
+.selected-unit {
+ font-weight: bold;
+}
+
+/* * * * * * Price details * * * * * */
+
+#display-price-details .price-details-list {
+ padding-left: 0px;
+}
+
+#display-price-details .price-details-list li {
+ list-style: none;
+}
+
+#display-price-details .price-details-list li .price-detail-name {
+ width: 200px;
+}
+
+#display-price-details .price-details-list li .price-detail-name,
+#display-price-details .price-details-list li .price-detail-price {
+ display: inline-block;
+}
+
+#manage-product-details-form .formfieldline {
+ white-space: nowrap;
+}
+
+#manage-product-details-form .formlabel,
+#manage-product-details-form .formfield {
+ display: inline-block;
+}
+
+#manage-product-details-form #add-new-cost {
+ float: right;
+}
+
+/* * * Progress bar on price details edition * * */
+
+#display-manage-price-details .ui-widget-content {
+ border: 1px solid #DDD;
+}
+
+#display-manage-price-details .ui-progressbar {
+ height: 20px;
+}
+
+#display-manage-price-details .ui-progressbar .ui-progressbar-value {
+ margin: 0px;
+ background-color: #A40000;
+ filter:alpha(opacity=70);
+ -moz-opacity: 0.7;
+ opacity: 0.7;
+}
+
+#display-manage-price-details .ui-progressbar .ui-progressbar-value.price-described {
+ background-color: #4E9A06;
+}
+
+#display-manage-price-details #price-details-info {
+ margin: 10px 0px;
+}
+
+#display-manage-price-details #details-progressbar {
+ position: relative;
+ width: 410px;
+ display: inline-block;
+}
+
+#display-manage-price-details #progressbar-text {
+ position: absolute;
+ top: 5px;
+ right: 7px;
+ font-size: 11px;
+}
+
+#display-manage-price-details #progressbar-icon {
+ display: inline-block;
+ cursor: pointer;
+}
+
+#display-manage-price-details #details-progressbar .ui-corner-left,
+#display-manage-price-details #details-progressbar .ui-corner-right {
+ -moz-border-radius-bottomleft: 0px;
+ -moz-border-radius-bottomright: 0px;
+ -moz-border-radius-topleft: 0px;
+ -moz-border-radius-topright: 0px;
+}
+
diff --git a/plugins/products/public/stylesheets/product/categories-selection.scss b/plugins/products/public/stylesheets/product/categories-selection.scss
new file mode 100644
index 0000000..37298f9
--- /dev/null
+++ b/plugins/products/public/stylesheets/product/categories-selection.scss
@@ -0,0 +1,61 @@
+#category_form {
+ border: 1px solid #AABB88;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ background: url(../images/ccc.gif); /* image ccc.gif from http://www.wannabegirl.org/translucent */
+ padding: 10px 30px 20px 30px;
+}
+#categories_container_wrapper {
+ overflow-x: scroll;
+ margin: 10px 0 15px 0;
+ padding: 5px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ background: url(../images/fff.gif); /* image fff.gif from http://www.wannabegirl.org/translucent */
+ border: 1px solid #CCC;
+ border-bottom: 0;
+ position: relative;
+}
+.categories_container {
+ min-height: 176px;
+ display: inline-block;
+ position: relative;
+}
+.categories_container .categories_container {
+ position: absolute;
+ top: 0;
+ left: 100%;
+}
+.msie .categories_container .categories_container {
+ left: auto;
+}
+.categories_container select {
+ margin-right: 10px;
+ height: 176px;
+ font-size: 11px;
+}
+.controller-manage_products #categories_selection_actionbar input.button {
+ height: 23px !important;
+}
+#save_and_continue_wrapper {
+ position: relative;
+}
+#save_and_continue_disabled_tooltip {
+ display: none;
+ position: absolute;
+ top: 30px;
+ left: 0;
+ min-width: 250px;
+}
+.msie #save_and_continue_disabled_tooltip {
+ font-size: small;
+}
+#save_and_continue_wrapper #save_and_continue.disabled:hover + #save_and_continue_disabled_tooltip {
+ display: block;
+}
+#hierarchy_navigation {
+ min-height: 1.3em;
+}
+.msie #hierarchy_navigation {
+ font-size: small;
+}
diff --git a/plugins/products/public/stylesheets/product/inputs.scss b/plugins/products/public/stylesheets/product/inputs.scss
new file mode 100644
index 0000000..fed1e47
--- /dev/null
+++ b/plugins/products/public/stylesheets/product/inputs.scss
@@ -0,0 +1,101 @@
+
+#product-qualifiers, .input-list {
+ padding: 0;
+ margin-left: 0;
+ position: relative;
+}
+.input-list-header {
+ font-weight: bold;
+ margin-top: 10px;
+}
+#content .main-block #product-inputs .input-list .input-item {
+ text-align: left;
+}
+#content .main-block #product-qualifiers .product-qualifiers-item, #content .main-block #product-inputs .input-list .input-item, #content .main-block #show_product .input-list li, #content .main-block #show_product .ui-tabs ul .tab {
+ list-style: none;
+ list-style-image: none;
+}
+#product-qualifiers-list .icon-delete span {
+ display: none;
+}
+.input-item {
+ min-height: 40px;
+ margin: 15px 0;
+ position: relative;
+ border: 1px solid transparent;
+}
+.msie .input-list .ui-state-highlight {
+ height: 40px;
+}
+.input-item .button-bar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 3px 0;
+}
+.input-details-form form {
+ border: 1px dashed #EFEFEF;
+ padding: 2px 0 5px 5px;
+ margin-left: -5px;
+}
+.input-form-opened {
+ border: 1px solid gray;
+}
+.input-form-closed {
+ border: 0;
+}
+.input-details-form .amount-used {
+ width: 70px;
+ margin-right: 6px;
+}
+.input-details-form .price-per-unit {
+ width: 110px;
+}
+.input-details-form table {
+ width: auto;
+}
+#product-info-form tr:hover td, .input-details-form tr:hover td {
+ background: none;
+}
+#product-info-form tr td, .input-details-form tr th, .input-details-form tr td {
+ height: auto;
+ border: none;
+ padding: 2px 0;
+}
+#product-info-form tr .formlabel, .input-details-form tr .formlabel {
+ max-width: 195px;
+}
+.input-details-form .selected-unit {
+ padding: 0 2px;
+}
+.input-informations {
+ padding: 5px 0 5px 5px;
+}
+.editing-input {
+ border: 1px dotted #BBB;
+}
+.input-name {
+ width: 240px;
+}
+.input-name, .input-details {
+ display: inline-block;
+}
+.input-details {
+ width: 190px;
+}
+.input-list-header .input-details {
+ width: auto;
+}
+.add-input-details {
+ position: absolute;
+ left: 5px;
+ top: 20px;
+}
+#content .main-block #product-inputs .input-list .remove-input, #content .main-block #product-inputs .input-list .edit-input {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+.solidatiry-economy-icon {
+ vertical-align: middle;
+ padding: 0 3px;
+}
diff --git a/plugins/products/public/stylesheets/style.scss b/plugins/products/public/stylesheets/style.scss
new file mode 100644
index 0000000..0cfa3f4
--- /dev/null
+++ b/plugins/products/public/stylesheets/style.scss
@@ -0,0 +1,8 @@
+@import 'blocks/featured-products';
+@import 'blocks/products';
+
+@import 'product-category';
+@import 'product';
+
+@import 'catalog';
+
diff --git a/plugins/products/script/sample-products b/plugins/products/script/sample-products
new file mode 100755
index 0000000..a9c31c2
--- /dev/null
+++ b/plugins/products/script/sample-products
@@ -0,0 +1,43 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/../config/environment'
+include Noosfero::SampleDataHelper
+
+enterprises = $environment.enterprises
+categories = $environment.product_categories
+
+print "Creating products: "
+THINGS = %w[ Car House Bicycle Book Pen Computer Webcam ]
+COLORS = %w[ Black Red White Blue Green Purple ]
+for thing in THINGS
+ for color in COLORS
+ name = [color, thing].join(' ')
+ rand(10).times do |i|
+ profile = enterprises.sample
+ next if profile.products.where(:name => name).first
+ product = Product.new
+ product.name = name
+ product.profile_id = profile.id
+ product.price = (i * 13.7)
+ product.product_category_id = categories.sample.id
+ save product
+ end
+ end
+end
+done
+
+print "Creating qualifiers and certifier: "
+QUALIFIERS = ['Organic', 'Free as in Freedom', 'Regional']
+CERTIFIERS = ['FBES', 'Colivre', 'Institute Paulo Freire', 'Fora do Eixo']
+for qualifier in QUALIFIERS
+ save Qualifier.new(:name => qualifier, :environment => $environment)
+end
+for certifier in CERTIFIERS
+ save Certifier.new(:name => certifier, :environment => $environment)
+end
+done
+
+print "Creating units: "
+[['Litre', 'Litres'], ['Kilo', 'Kilos'], ['Meter', 'Meters']].each do |unit|
+ save Unit.new(:singular => unit[0], :plural => unit[1], :environment => $environment)
+end
+done
diff --git a/plugins/products/test/functional/products_plugin/catalog_controller_test.rb b/plugins/products/test/functional/products_plugin/catalog_controller_test.rb
new file mode 100644
index 0000000..45f69e9
--- /dev/null
+++ b/plugins/products/test/functional/products_plugin/catalog_controller_test.rb
@@ -0,0 +1,209 @@
+require_relative '../../test_helper'
+
+class CatalogControllerTest < ActionController::TestCase
+ def setup
+ @controller = ProductsPlugin::CatalogController.new
+
+ @enterprise = fast_create(Enterprise, name: 'My enterprise', identifier: 'testent')
+ @product_category = create(ProductsPlugin::ProductCategory)
+ end
+ attr_accessor :enterprise
+
+ should 'not display for non-enterprises' do
+ u = create_user('testinguser').person
+ get :index, profile: 'testinguser'
+ assert_redirected_to controller: "profile", profile: 'testinguser', action: 'index'
+ end
+
+ should 'display for enterprises' do
+ get :index, profile: 'testent'
+ assert_response :success
+ end
+
+ should 'list products of enterprise' do
+ get :index, profile: @enterprise.identifier
+ assert assigns(:products)
+ end
+
+ should 'paginate enterprise products list' do
+ 1.upto(12).map do
+ fast_create(Product, profile_id: @enterprise.id)
+ end
+
+ assert_equal 12, @enterprise.products.count
+ get :index, profile: @enterprise.identifier
+ assert_equal 6, assigns(:products).size
+ assert_tag :a, attributes: {class: 'next_page'}
+ end
+
+ should 'not show product price when listing products if not informed' do
+ prod = @enterprise.products.create!(name: 'Product test', product_category: @product_category)
+ get :index, profile: @enterprise.identifier
+ assert_no_tag tag: 'span', attributes: { class: 'product-price with-discount' }, content: /50.00/
+ end
+
+ should 'show product price when listing products if informed' do
+ prod = @enterprise.products.create!(name: 'Product test', price: 50.00, product_category: @product_category)
+ get :index, profile: @enterprise.identifier
+ assert_tag tag: 'span', attributes: { class: 'product-price with-discount' }, content: /50.00/
+ end
+
+ should 'show action moved to manage_products controller' do
+ assert_raise ActionController::UrlGenerationError do
+ get :show, id: 1
+ end
+ end
+
+ should 'include extra content supplied by plugins on catalog item extras' do
+ class Plugin1 < Noosfero::Plugin
+ def catalog_item_extras(product)
+ proc {"This is Plugin1 speaking! ".html_safe}
+ end
+ end
+
+ class Plugin2 < Noosfero::Plugin
+ def catalog_item_extras(product)
+ proc {"This is Plugin2 speaking! ".html_safe}
+ end
+ end
+ Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
+
+ product = fast_create(Product, profile_id: @enterprise.id)
+ environment = Environment.default
+ environment.enable_plugin(Plugin1.name)
+ environment.enable_plugin(Plugin2.name)
+
+ get :index, profile: @enterprise.identifier
+
+ assert_tag tag: 'span', content: 'This is Plugin1 speaking!', attributes: {id: 'plugin1'}
+ assert_tag tag: 'span', content: 'This is Plugin2 speaking!', attributes: {id: 'plugin2'}
+ end
+
+ should 'get categories of the right level' do
+ pc1 = create(ProductCategory, name: "PC1", environment: @enterprise.environment)
+ pc2 = create(ProductCategory, name: "PC2", environment: @enterprise.environment, parent_id: pc1.id)
+ pc3 = create(ProductCategory, name: "PC3", environment: @enterprise.environment, parent_id: pc1.id)
+ pc4 = create(ProductCategory, name: "PC4", environment: @enterprise.environment, parent_id: pc2.id)
+ p1 = fast_create(Product, product_category_id: pc1.id, profile_id: @enterprise.id)
+ p2 = fast_create(Product, product_category_id: pc2.id, profile_id: @enterprise.id)
+ p3 = fast_create(Product, product_category_id: pc3.id, profile_id: @enterprise.id)
+ p4 = fast_create(Product, product_category_id: pc4.id, profile_id: @enterprise.id)
+
+ get :index, profile: @enterprise.identifier, level: pc1.id
+
+ assert_not_includes assigns(:categories), pc1
+ assert_includes assigns(:categories), pc2
+ assert_includes assigns(:categories), pc3
+ assert_not_includes assigns(:categories), pc4
+ end
+
+ should 'filter products based on level selected' do
+ pc1 = ProductCategory.create!(name: "PC1", environment: @enterprise.environment)
+ pc2 = ProductCategory.create!(name: "PC2", environment: @enterprise.environment, parent_id: pc1.id)
+ pc3 = ProductCategory.create!(name: "PC3", environment: @enterprise.environment, parent_id: pc1.id)
+ pc4 = ProductCategory.create!(name: "PC4", environment: @enterprise.environment, parent_id: pc2.id)
+ p1 = fast_create(Product, product_category_id: pc1.id, profile_id: @enterprise.id)
+ p2 = fast_create(Product, product_category_id: pc2.id, profile_id: @enterprise.id)
+ p3 = fast_create(Product, product_category_id: pc3.id, profile_id: @enterprise.id)
+ p4 = fast_create(Product, product_category_id: pc4.id, profile_id: @enterprise.id)
+
+ get :index, profile: @enterprise.identifier, level: pc2.id
+
+ assert_not_includes assigns(:products), p1
+ assert_includes assigns(:products), p2
+ assert_not_includes assigns(:products), p3
+ assert_includes assigns(:products), p4
+ end
+
+ should 'get products ordered by availability, highlighted and then name' do
+ p1 = fast_create(Product, profile_id: @enterprise.id, name: 'Zebra', available: true, highlighted: true)
+ p2 = fast_create(Product, profile_id: @enterprise.id, name: 'Car', available: true)
+ p3 = fast_create(Product, profile_id: @enterprise.id, name: 'Panda', available: true)
+ p4 = fast_create(Product, profile_id: @enterprise.id, name: 'Pen', available: false, highlighted: true)
+ p5 = fast_create(Product, profile_id: @enterprise.id, name: 'Ball', available: false)
+ p6 = fast_create(Product, profile_id: @enterprise.id, name: 'Medal', available: false)
+
+ get :index, profile: @enterprise.identifier
+
+ assert_equal [p1,p2,p3,p4,p5,p6], assigns(:products)
+ end
+
+ should 'add highlighted CSS class around a highlighted product' do
+ prod = @enterprise.products.create!(name: 'Highlighted Product', product_category: @product_category, highlighted: true)
+ get :index, profile: @enterprise.identifier
+ assert_tag tag: 'li', attributes: { class: 'product highlighted' }, content: /Highlighted Product/
+ end
+
+ should 'do not add highlighted CSS class around an ordinary product' do
+ prod = @enterprise.products.create!(name: 'Ordinary Product', product_category: @product_category, highlighted: false)
+ get :index, profile: @enterprise.identifier
+ assert_no_tag tag: 'li', attributes: { class: 'product highlighted' }, content: /Ordinary Product/
+ end
+
+ should 'display star image in highlighted product' do
+ prod = @enterprise.products.create!(name: 'The Eyes Are The Light', product_category: @product_category, highlighted: true)
+ get :index, profile: @enterprise.identifier
+ assert_tag tag: 'img', attributes: { class: 'star', src: /star.png/ }
+ end
+
+ should 'display categories on breadcrumb' do
+ pc1 = create(ProductCategory, name: "PC1", environment: @enterprise.environment)
+ pc2 = create(ProductCategory, name: "PC2", environment: @enterprise.environment, parent_id: pc1.id)
+ pc3 = create(ProductCategory, name: "PC3", environment: @enterprise.environment, parent_id: pc1.id)
+ pc4 = create(ProductCategory, name: "PC4", environment: @enterprise.environment, parent_id: pc2.id)
+ p1 = fast_create(Product, product_category_id: pc1.id, profile_id: @enterprise.id)
+ p2 = fast_create(Product, product_category_id: pc2.id, profile_id: @enterprise.id)
+ p3 = fast_create(Product, product_category_id: pc3.id, profile_id: @enterprise.id)
+ p4 = fast_create(Product, product_category_id: pc4.id, profile_id: @enterprise.id)
+
+ get :index, profile: @enterprise.identifier, level: pc4.id
+
+ assert_tag tag: 'div', attributes: {id: 'breadcrumb'}, descendant: {tag: 'a', attributes: {href: /level=#{pc1.id}/}}
+ assert_tag tag: 'div', attributes: {id: 'breadcrumb'}, descendant: {tag: 'a', attributes: {href: /level=#{pc2.id}/}}
+ assert_tag tag: 'div', attributes: {id: 'breadcrumb'}, descendant: {tag: 'strong', content: pc4.name}
+ assert_no_tag tag: 'div', attributes: {id: 'breadcrumb'}, descendant: {tag: 'a', attributes: {href: /level=#{pc3.id}/}}
+ end
+
+ should 'add product status on the class css' do
+ category = create(ProductCategory, name: "Cateogry", environment: @enterprise.environment)
+ p1 = fast_create(Product, product_category_id: category.id, profile_id: @enterprise.id, highlighted: true)
+ p2 = fast_create(Product, product_category_id: category.id, profile_id: @enterprise.id, available: false)
+
+ get :index, profile: @enterprise.identifier
+
+ assert_tag tag: 'li', attributes: {id: "product-#{p1.id}", class: /highlighted/}
+ assert_tag tag: 'li', attributes: {id: "product-#{p2.id}", class: /not-available/}
+ end
+
+ should 'sort categories by name' do
+ environment = @enterprise.environment
+ environment.categories.destroy_all
+ pc1 = create(ProductCategory, name: "Drinks", environment: environment)
+ pc2 = create(ProductCategory, name: "Bananas", environment: environment)
+ pc3 = create(ProductCategory, name: "Sodas", environment: environment)
+ pc4 = create(ProductCategory, name: "Pies", environment: environment)
+ p1 = fast_create(Product, product_category_id: pc1.id, profile_id: @enterprise.id)
+ p2 = fast_create(Product, product_category_id: pc2.id, profile_id: @enterprise.id)
+ p3 = fast_create(Product, product_category_id: pc3.id, profile_id: @enterprise.id)
+ p4 = fast_create(Product, product_category_id: pc4.id, profile_id: @enterprise.id)
+
+ get :index, profile: @enterprise.identifier
+
+ assert_equal [pc2, pc1, pc4, pc3], assigns(:categories)
+ end
+
+ should 'use price_detail name instead of production_cost name straight' do
+ p1 = fast_create(Product, product_category_id: @product_category.id, profile_id: @enterprise.id)
+ p2 = fast_create(Product, product_category_id: @product_category.id, profile_id: @enterprise.id)
+ Product.any_instance.stubs(:price_described?).returns(true)
+ production_cost = fast_create(ProductionCost)
+ pd1 = create(PriceDetail, product: p1, production_cost_id: production_cost.id)
+ pd2 = create(PriceDetail, product: p2)
+
+ get :index, profile: @enterprise.identifier
+
+ assert_tag tag: 'div', attributes: {class: 'search-product-input-name'}, content: production_cost.name
+ assert_tag tag: 'div', attributes: {class: 'search-product-input-name'}, content: 'Other costs'
+ end
+
+end
diff --git a/plugins/products/test/functional/products_plugin/page_controller_test.rb b/plugins/products/test/functional/products_plugin/page_controller_test.rb
new file mode 100644
index 0000000..679cb9f
--- /dev/null
+++ b/plugins/products/test/functional/products_plugin/page_controller_test.rb
@@ -0,0 +1,480 @@
+require_relative '../../test_helper'
+
+class PageControllerTest < ActionController::TestCase
+
+ all_fixtures
+
+ def setup
+ @controller = ProductsPlugin::PageController.new
+ @enterprise = fast_create Enterprise, name: 'teste', identifier: 'test_ent'
+ @environment = @enterprise.environment
+ @user = create_user_with_permission 'test_user', 'manage_products', @enterprise
+ @product_category = create ProductCategory, name: 'Root Category', environment_id: @environment.id
+ @unit = Unit.create environment: @environment
+
+ login_as :test_user
+ end
+
+ should "not have permission" do
+ u = create_user('user_test')
+ login_as :user_test
+ get 'index', profile: @enterprise.identifier
+ assert :success
+ assert_template 'shared/access_denied'
+ end
+
+ should "get index" do
+ get 'index', profile: @enterprise.identifier
+ assert_response :success
+ assert assigns(:products)
+ end
+
+ should "get new form" do
+ get 'new', profile: @enterprise.identifier
+ assert_response :success
+ assert assigns(:product)
+ assert_template 'new'
+ assert_tag tag: 'form', attributes: { action: /new/ }
+ end
+
+ should "create new product" do
+ assert_difference 'Product.count' do
+ post 'new', profile: @enterprise.identifier, product: {name: 'test product'}, selected_category_id: @product_category.id
+ assert assigns(:product)
+ refute assigns(:product).new_record?
+ end
+ end
+
+ should "not create invalid product" do
+ assert_no_difference 'Product.count' do
+ post 'new', profile: @enterprise.identifier, product: {name: 'test product'}
+ assert_response :success
+ assert assigns(:product)
+ assert assigns(:product).new_record?
+ end
+ end
+
+ should "get edit name form" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get 'edit', profile: @enterprise.identifier, id: product.id, field: 'name'
+ assert_response :success
+ assert assigns(:product)
+ assert_tag tag: 'form', attributes: { action: /profile\/#{@enterprise.identifier}\/plugin\/products\/page\/edit\/#{product.id}\?field=name/ }
+ end
+
+ should "get edit info form" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get 'edit', profile: @enterprise.identifier, id: product.id, field: 'info'
+ assert_response :success
+ assert assigns(:product)
+ assert_tag tag: 'form', attributes: { action: /profile\/#{@enterprise.identifier}\/plugin\/products\/page\/edit\/#{product.id}\?field=info/ }
+ end
+
+ should "get edit image form" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get 'edit', profile: @enterprise.identifier, id: product.id, field: 'image'
+ assert_response :success
+ assert assigns(:product)
+ assert_tag tag: 'form', attributes: { action: /profile\/#{@enterprise.identifier}\/plugin\/products\/page\/edit\/#{product.id}\?field=image/ }
+ end
+
+ should "edit product name" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ post :edit, profile: @enterprise.identifier, product: {name: 'new test product'}, id: product.id, field: 'name'
+ assert_response :success
+ assert assigns(:product)
+ refute assigns(:product).new_record?
+ assert_equal product, Product.find_by(name: 'new test product')
+ end
+
+ should "edit product description" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id, description: 'My product is very good')
+ post :edit, profile: @enterprise.identifier, product: {description: 'A very good product!'}, id: product.id, field: 'info'
+ assert_response :success
+ assert assigns(:product)
+ refute assigns(:product).new_record?
+ assert_equal 'A very good product!', Product.find_by(name: 'test product').description
+ end
+
+ should "edit product image" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ post :edit, profile: @enterprise.identifier, product: { image_builder: { uploaded_data: fixture_file_upload('/files/rails.png', 'image/png') } }, id: product.id, field: 'image'
+ assert_response :success
+ assert assigns(:product)
+ refute assigns(:product).new_record?
+ assert_equal 'rails.png', Product.find_by(name: 'test product').image.filename
+ end
+
+ should "not edit to invalid parameters" do
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ post 'edit_category', profile: @enterprise.identifier, selected_category_id: nil, id: product.id
+ assert_response :success
+ assert_template 'shared/_dialog_error_messages'
+ end
+
+ should "not crash if product has no category" do
+ product = fast_create(Product, profile_id: @enterprise.id)
+ assert_nothing_raised do
+ post 'edit_category', profile: @enterprise.identifier, id: product.id
+ end
+ end
+
+ should "destroy product" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ assert_difference 'Product.count', -1 do
+ post 'destroy', profile: @enterprise.identifier, id: product.id
+ assert_response :redirect
+ assert_redirected_to action: 'index'
+ assert assigns(:product)
+ refute Product.find_by(name: 'test product')
+ end
+ end
+
+ should "fail to destroy product" do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ Product.any_instance.stubs(:destroy).returns(false)
+ assert_no_difference 'Product.count' do
+ post 'destroy', profile: @enterprise.identifier, id: product.id
+ assert_response :redirect
+ assert_redirected_to controller: "products_plugin/page", profile: @enterprise.identifier, action: 'show', id: product.id
+ assert assigns(:product)
+ assert Product.find_by(name: 'test product')
+ end
+ end
+
+ should 'show categories selection' do
+ create ProductCategory, name: 'Category 2', parent_id: @product_category.id
+ get :new, profile: @enterprise.identifier
+ assert_tag tag: 'select', attributes: { id: 'category_id' }, descendant: { tag: 'option', content: /#{@product_category.name}/ }
+ end
+
+ should "create new product categorized" do
+ category2 = fast_create(ProductCategory, name: 'Category 2', parent_id: @product_category)
+ assert_difference 'Product.count' do
+ post 'new', profile: @enterprise.identifier, product: { name: 'test product' }, selected_category_id: category2.id
+ assert_equal category2, assigns(:product).product_category
+ end
+ end
+
+ should 'not create a new product with an invalid category' do
+ category2 = create(Category, name: 'Category 2', parent_id: @product_category)
+ assert_raise ActiveRecord::AssociationTypeMismatch do
+ post 'new', profile: @enterprise.identifier, product: { name: 'test product' }, selected_category_id: category2.id
+ end
+ end
+
+ should 'filter html from name of product' do
+ post 'new', profile: @enterprise.identifier, product: { name: "name bold " }, selected_category_id: @product_category.id
+ assert_sanitized assigns(:product).name
+ end
+
+ should 'filter html with white list from description of product' do
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ post 'edit', profile: @enterprise.identifier, id: product.id, field: 'info', product: { name: 'name', description: "descr bold " }
+ assert_equal "descr bold ", assigns(:product).description
+ end
+
+ should 'show top level product categories for the user to choose' do
+ pc2 = create(ProductCategory, name: 'test_category2')
+
+ get :new, profile: @enterprise.identifier
+
+ assert_equivalent ProductCategory.top_level_for(@product_category.environment), assigns(:categories)
+ end
+
+ should 'increase level while navigate on hierarchy categories' do
+ category_level1 = create ProductCategory, parent_id: @product_category.id, name: 'Shoes', environment_id: @environment.id
+ category_level2 = create ProductCategory, parent_id: category_level1.id, name: 'Athletic Shoes', environment_id: @environment.id
+
+ get :categories_for_selection, profile: @enterprise.identifier, category_id: nil
+ assert_equal 0, assigns(:level)
+
+ get :categories_for_selection, profile: @enterprise.identifier, category_id: @product_category.id
+ assert_equal 1, assigns(:level)
+
+ get :categories_for_selection, profile: @enterprise.identifier, category_id: category_level1.id
+ assert_equal 2, assigns(:level)
+ end
+
+ should 'remember the selected category' do
+ category2 = create ProductCategory, name: 'Shoes', environment_id: @environment.id
+
+ get :categories_for_selection, profile: @enterprise.identifier, category_id: @product_category.id
+ assert_equal @product_category, assigns(:category)
+
+ get :categories_for_selection, profile: @enterprise.identifier, category_id: category2.id
+ assert_equal category2, assigns(:category)
+ end
+
+ should 'list top level categories when has no category_id' do
+ get :categories_for_selection, profile: @enterprise.identifier
+
+ assert_equal ProductCategory.top_level_for(@environment), assigns(:categories)
+ end
+
+ should 'render dialog_error_messages template for invalid product' do
+ post :new, profile: @enterprise.identifier, product: { name: 'Invalid product' }
+ assert_template 'shared/_dialog_error_messages'
+ end
+
+ should 'render redirect_via_javascript template after save' do
+ assert_difference 'Product.count' do
+ post :new, profile: @enterprise.identifier, product: { name: 'Invalid product' }, selected_category_id: @product_category.id
+ assert_template 'shared/_redirect_via_javascript'
+ end
+ end
+
+ should 'show product of enterprise' do
+ prod = @enterprise.products.create!(name: 'Product test', product_category: @product_category)
+ get :show, id: prod.id, profile: @enterprise.identifier
+ assert_tag tag: 'h2', content: /#{prod.name}/
+ end
+
+ should 'link back to index from product show' do
+ enterprise = create(Enterprise, name: 'test_enterprise_1', identifier: 'test_enterprise_1', environment: Environment.default)
+ prod = enterprise.products.create!(name: 'Product test', product_category: @product_category)
+ get :show, id: prod.id, profile: enterprise.identifier
+ assert_tag({
+ tag: 'a',
+ attributes: {
+ href: /profile\/#{enterprise.identifier}\/plugin\/products\/catalog/
+ },
+ content: /Back to the product listing/,
+ })
+ end
+
+ should 'not show product price when showing product if not informed' do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_no_tag tag: 'span', attributes: { class: 'product_price' }, content: /Price:/
+ end
+
+ should 'show product price when showing product if unit was informed' do
+ product = fast_create(Product, name: 'test product', price: 50.00, unit_id: @unit.id, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'span', attributes: { class: 'field-name' }, content: /Price:/
+ assert_tag tag: 'span', attributes: { class: 'field-value' }, content: '$ 50.00'
+ end
+
+ should 'show product price when showing product if discount was informed' do
+ product = fast_create(Product, name: 'test product', price: 50.00, unit_id: @unit.id, discount: 3.50, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'span', attributes: { class: 'field-name' }, content: /List price:/
+ assert_tag tag: 'span', attributes: { class: 'field-value' }, content: '$ 50.00'
+ assert_tag tag: 'span', attributes: { class: 'field-name' }, content: /On sale:/
+ assert_tag tag: 'span', attributes: { class: 'field-value' }, content: '$ 46.50'
+ end
+
+ should 'show product price when showing product if unit not informed' do
+ product = fast_create(Product, name: 'test product', price: 50.00, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'span', attributes: { class: 'field-name' }, content: /Price:/
+ assert_tag tag: 'span', attributes: { class: 'field-value' }, content: '$ 50.00'
+ end
+
+ should 'display button to add input when product has no input' do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'div', attributes: { id: 'display-add-input-button'},
+ descendant: {tag: 'a', attributes: { href: /\/profile\/#{@enterprise.identifier}\/plugin\/products\/page\/add_input\/#{product.id}/, id: 'add-input-button'}, content: 'Add the inputs or raw material used by this product'}
+ end
+
+ should 'has instance of input list when showing product' do
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+ assert_equal [], assigns(:inputs)
+ end
+
+ should 'remove input of a product' do
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ input = fast_create(Input, product_id: product.id, product_category_id: @product_category.id)
+ assert_equal [input], product.inputs
+
+ post :remove_input, id: input.id, profile: @enterprise.identifier
+ product.reload
+ assert_equal [], product.inputs
+ end
+
+ should 'save inputs order' do
+ product = fast_create(Product, profile_id: @enterprise.id)
+ first = Input.create!(product: product, product_category: fast_create(ProductCategory))
+ second = Input.create!(product: product, product_category: fast_create(ProductCategory))
+ third = Input.create!(product: product, product_category: fast_create(ProductCategory))
+
+ assert_equal [first, second, third], product.inputs(true)
+
+ get :order_inputs, profile: @enterprise.identifier, id: product, input: [second.id, third.id, first.id]
+ assert_template nil
+
+ assert_equal [second, third, first], product.inputs(true)
+ end
+
+ should 'render partial certifiers for selection' do
+ xhr :get, :certifiers_for_selection, profile: @enterprise.identifier
+ assert_template '_certifiers_for_selection'
+ end
+
+ should 'not list all the products of enterprise' do
+ @enterprise.products = []
+ 1.upto(12) do |n|
+ fast_create(Product, name: "test product_#{n}", profile_id: @enterprise.id, product_category_id: @product_category.id)
+ end
+ get :index, profile: @enterprise.identifier
+ assert_equal 10, assigns(:products).size
+ end
+
+ should 'paginate the manage products list of enterprise' do
+ @enterprise.products = []
+ 1.upto(12) do |n|
+ fast_create(Product, name: "test product_#{n}", profile_id: @enterprise.id, product_category_id: @product_category.id)
+ end
+ get :index, profile: @enterprise.identifier
+ assert_tag tag: 'a', attributes: { rel: 'next', href: "/profile/#{@enterprise.identifier}/plugin/products/page?page=2" }
+
+ get :index, profile: @enterprise.identifier, page: 2
+ assert_equal 2, assigns(:products).size
+ end
+
+ should 'display tabs even if description and inputs are empty and user is allowed' do
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }
+ end
+
+ should 'not display tabs if description and inputs are empty and user is not allowed' do
+ create_user('foo')
+
+ login_as 'foo'
+
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_no_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }
+ end
+
+ should 'not display tabs if description and inputs are empty and user is not logged in' do
+ logout
+
+ product = fast_create(Product, name: 'test product', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_no_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }
+ end
+
+ should 'display only description tab if inputs are empty and user is not allowed' do
+ create_user('foo')
+
+ login_as 'foo'
+ product = fast_create(Product, description: 'This product is very good', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ get :show, id: product.id, profile: @enterprise.identifier
+ assert_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#product-description'}, content: 'Description'}
+ assert_no_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#inputs'}, content: 'Inputs and raw material'}
+ end
+
+ should 'display only inputs tab if description is empty and user is not allowed' do
+ create_user 'foo'
+
+ login_as 'foo'
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ input = fast_create(Input, product_id: product.id, product_category_id: @product_category.id)
+
+ get :show, id: product.id, profile: @enterprise.identifier
+ assert_no_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#product-description'}, content: 'Description'}
+ assert_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#product-inputs'}, content: 'Inputs and raw material'}
+ end
+
+ should 'display tabs if description and inputs are not empty and user is not allowed' do
+ create_user('foo')
+
+ login_as 'foo'
+ product = fast_create(Product, description: 'This product is very good', profile_id: @enterprise.id, product_category_id: @product_category.id)
+ input = fast_create(Input, product_id: product.id, product_category_id: @product_category.id)
+
+ get :show, id: product.id, profile: @enterprise.identifier
+ assert_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#product-description'}, content: 'Description'}
+ assert_tag tag: 'div', attributes: { id: "product-#{product.id}-tabs" }, descendant: {tag: 'a', attributes: {href: '#product-inputs'}, content: 'Inputs and raw material'}
+ end
+
+ should 'include extra content supplied by plugins on products info extras' do
+ class TestProductInfoExtras1Plugin < Noosfero::Plugin
+ def product_info_extras(p)
+ proc {"This is Plugin1 speaking! ".html_safe}
+ end
+ end
+ class TestProductInfoExtras2Plugin < Noosfero::Plugin
+ def product_info_extras(p)
+ proc { "This is Plugin2 speaking! ".html_safe}
+ end
+ end
+
+ product = fast_create(Product, profile_id: @enterprise.id)
+
+ Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestProductInfoExtras1Plugin.new, TestProductInfoExtras2Plugin.new])
+
+ get :show, id: product.id, profile: @enterprise.identifier
+
+ assert_tag tag: 'span', content: 'This is Plugin1 speaking!', attributes: {id: 'plugin1'}
+ assert_tag tag: 'span', content: 'This is Plugin2 speaking!', attributes: {id: 'plugin2'}
+ end
+
+ should 'not allow product creation for profiles that can\'t do it' do
+ class SpecialEnterprise < Enterprise
+ def create_product?
+ false
+ end
+ end
+ enterprise = SpecialEnterprise.create!(identifier: 'special-enterprise', name: 'Special Enterprise')
+ get 'new', profile: enterprise.identifier
+ assert_response 403
+ end
+
+ should 'remove price detail of a product' do
+ product = fast_create(Product, profile_id: @enterprise.id, product_category_id: @product_category.id)
+ cost = fast_create(ProductionCost, owner_id: Environment.default.id, owner_type: 'Environment')
+ detail = product.price_details.create(production_cost_id: cost.id, price: 10)
+
+ assert_equal [detail], product.price_details
+
+ post :remove_price_detail, id: detail.id, product: product, profile: @enterprise.identifier
+ product.reload
+ assert_equal [], product.price_details
+ end
+
+ should 'create a production cost for enterprise' do
+ get :create_production_cost, profile: @enterprise.identifier, id: 'Taxes'
+
+ assert_equal ['Taxes'], Enterprise.find(@enterprise.id).production_costs.map(&:name)
+ resp = ActiveSupport::JSON.decode(@response.body)
+ assert_equal 'Taxes', resp['name']
+ assert resp['id'].kind_of?(Integer)
+ assert resp['ok']
+ assert_nil resp['error_msg']
+ end
+
+ should 'display error if production cost has no name' do
+ get :create_production_cost, profile: @enterprise.identifier
+
+ resp = ActiveSupport::JSON.decode(@response.body)
+ assert_nil resp['name']
+ assert_nil resp['id']
+ refute resp['ok']
+ assert_match /blank/, resp['error_msg']
+ end
+
+ should 'display error if name of production cost is too long' do
+ get :create_production_cost, profile: @enterprise.identifier, id: 'a'*60
+
+ resp = ActiveSupport::JSON.decode(@response.body)
+ assert_nil resp['name']
+ assert_nil resp['id']
+ refute resp['ok']
+ assert_match /too long/, resp['error_msg']
+ end
+
+end
diff --git a/plugins/products/test/functional/products_plugin/search_controller_test.rb b/plugins/products/test/functional/products_plugin/search_controller_test.rb
new file mode 100644
index 0000000..b4885b7
--- /dev/null
+++ b/plugins/products/test/functional/products_plugin/search_controller_test.rb
@@ -0,0 +1,146 @@
+require_relative '../../test_helper'
+
+module ProductsPlugin
+ class SearchControllerTest < ActionController::TestCase
+
+ def setup
+ @controller = SearchController.new
+ @product_category = create ProductCategory, name: 'prod cat test', environment: Environment.default
+ end
+
+ should 'include extra content supplied by plugins on product asset' do
+ class Plugin1 < Noosfero::Plugin
+ def asset_product_extras(product)
+ proc {"This is Plugin1 speaking! ".html_safe}
+ end
+ end
+
+ class Plugin2 < Noosfero::Plugin
+ def asset_product_extras(product)
+ proc {"This is Plugin2 speaking! ".html_safe}
+ end
+ end
+ Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin2.to_s])
+
+ enterprise = fast_create(Enterprise)
+ fast_create(Product, {profile_id: enterprise.id, name: "produto1", product_category_id: @product_category.id}, search: true)
+
+ e = Environment.default
+ e.enable_plugin(Plugin1.name)
+ e.enable_plugin(Plugin2.name)
+
+ get :products, query: 'produto1'
+
+ assert_tag tag: 'span', content: 'This is Plugin1 speaking!', attributes: {id: 'plugin1'}
+ assert_tag tag: 'span', content: 'This is Plugin2 speaking!', attributes: {id: 'plugin2'}
+ end
+
+ should 'search for products' do
+ ent = create_profile_with_optional_category(Enterprise, 'teste')
+ prod = ent.products.create!(name: 'a beautiful product', product_category: @product_category)
+ get :products, query: 'beautiful'
+ assert_includes assigns(:searches)[:products][:results], prod
+ end
+
+ should 'include extra properties of the product supplied by plugins' do
+ class Plugin1 < Noosfero::Plugin
+ def asset_product_properties(product)
+ return { name: _('Property1'), content: proc { link_to(product.name, '/plugin1') } }
+ end
+ end
+ class Plugin2 < Noosfero::Plugin
+ def asset_product_properties(product)
+ return { name: _('Property2'), content: proc { link_to(product.name, '/plugin2') } }
+ end
+ end
+ Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin2.to_s])
+ enterprise = fast_create(Enterprise)
+ product = fast_create(Product, {profile_id: enterprise.id, name: "produto1", product_category_id: @product_category.id}, search: true)
+
+ environment = Environment.default
+ environment.enable_plugin(Plugin1.name)
+ environment.enable_plugin(Plugin2.name)
+
+ get :products, query: "produto1"
+
+ assert_tag tag: 'div', content: /Property1/, child: {tag: 'a', attributes: {href: '/plugin1'}, content: product.name}
+ assert_tag tag: 'div', content: /Property2/, child: {tag: 'a', attributes: {href: '/plugin2'}, content: product.name}
+ end
+
+ should 'render specific action when only one asset is enabled' do
+ environment = Environment.default
+ # article is not disabled
+ [:enterprises, :people, :communities, :products, :events].select do |key, name|
+ environment.enable('disable_asset_' + key.to_s)
+ end
+ environment.save!
+ @controller.stubs(:environment).returns(environment)
+
+ get :index, query: 'something'
+
+ assert assigns(:searches).has_key?(:articles)
+ refute assigns(:searches).has_key?(:enterprises)
+ refute assigns(:searches).has_key?(:people)
+ refute assigns(:searches).has_key?(:communities)
+ refute assigns(:searches).has_key?(:products)
+ refute assigns(:searches).has_key?(:events)
+ end
+
+ should 'display only within a product category when specified' do
+ ent = create_profile_with_optional_category(Enterprise, 'test ent')
+
+ p = create(Product, product_category: @product_category, name: 'prod test 1', enterprise: ent)
+
+ get :products, product_category: @product_category.id
+
+ assert_includes assigns(:searches)[:products][:results], p
+ end
+
+ should 'display properly in conjuntion with a category' do
+ cat = create(Category, name: 'cat', environment: Environment.default)
+ prod_cat2 = create ProductCategory, name: 'prod cat test 2', environment: Environment.default, parent: @product_category1
+ ent = create_profile_with_optional_category(Enterprise, 'test ent', cat)
+
+ product = create(Product, product_category: prod_cat2, name: 'prod test 1', profile_id: ent.id)
+
+ get :products, category_path: cat.path.split('/'), product_category: @product_category.id
+
+ assert_includes assigns(:searches)[:products][:results], product
+ end
+
+ should 'find products when enterprises has own hostname' do
+ ent = create_profile_with_optional_category(Enterprise, 'teste')
+ ent.domains << Domain.new(name: 'testent.com'); ent.save!
+ prod = ent.products.create!(name: 'a beautiful product', product_category: @product_category)
+ get 'products', query: 'beautiful'
+ assert_includes assigns(:searches)[:products][:results], prod
+ end
+
+ should 'add script tag for google maps if searching products' do
+ get 'products', query: 'product', display: 'map'
+
+ assert_tag tag: 'script', attributes: { src: 'http://maps.google.com/maps/api/js?sensor=true'}
+ end
+
+ should 'add highlighted CSS class around a highlighted product' do
+ enterprise = fast_create(Enterprise)
+ product = create(Product, name: 'Enter Sandman', profile_id: enterprise.id, product_category_id: @product_category.id, highlighted: true)
+ get :products
+ assert_tag tag: 'li', attributes: { class: 'search-product-item highlighted' }, content: /Enter Sandman/
+ end
+
+ should 'do not add highlighted CSS class around an ordinary product' do
+ enterprise = fast_create(Enterprise)
+ product = create(Product, name: 'Holier Than Thou', profile_id: enterprise.id, product_category_id: @product_category.id, highlighted: false)
+ get :products
+ assert_no_tag tag: 'li', attributes: { class: 'search-product-item highlighted' }, content: /Holier Than Thou/
+ end
+
+ protected
+
+ def create_profile_with_optional_category klass, name, category = nil, data = {}
+ fast_create klass, { name: name }.merge(data), search: true, category: category
+ end
+
+ end
+end
diff --git a/plugins/products/test/functional/profile_design_controller_test.rb b/plugins/products/test/functional/profile_design_controller_test.rb
new file mode 100644
index 0000000..66b8caf
--- /dev/null
+++ b/plugins/products/test/functional/profile_design_controller_test.rb
@@ -0,0 +1,67 @@
+require_relative '../test_helper'
+
+class ProfileDesignControllerTest < ActionController::TestCase
+
+ def setup
+ @controller = ProfileDesignController.new
+ @product_category = create ProductCategory
+
+ @profile = @holder = create_user('designtestuser').person
+ holder.save!
+
+ @box1 = Box.new
+ @box2 = Box.new
+ @box3 = Box.new
+
+ holder.boxes << @box1
+ holder.boxes << @box2
+ holder.boxes << @box3
+
+ end
+ attr_reader :holder
+
+ should 'be able to edit ProductsBlock' do
+ block = ProductsBlock.new
+
+ enterprise = fast_create(Enterprise, name: "test", identifier: 'testenterprise')
+ enterprise.boxes << Box.new
+ p1 = enterprise.products.create!(name: 'product one', product_category: @product_category)
+ p2 = enterprise.products.create!(name: 'product two', product_category: @product_category)
+ enterprise.boxes.first.blocks << block
+ enterprise.add_admin(holder)
+
+ enterprise.blocks(true)
+ @controller.stubs(:boxes_holder).returns(enterprise)
+ login_as('designtestuser')
+
+ get :edit, profile: 'testenterprise', id: block.id
+
+ assert_response :success
+ assert_tag tag: 'input', attributes: { name: "block[product_ids][]", value: p1.id.to_s }
+ assert_tag tag: 'input', attributes: { name: "block[product_ids][]", value: p2.id.to_s }
+ end
+
+ should 'be able to save ProductsBlock' do
+ block = ProductsBlock.new
+
+ enterprise = fast_create(Enterprise, name: "test", identifier: 'testenterprise')
+ enterprise.boxes << Box.new
+ p1 = enterprise.products.create!(name: 'product one', product_category: @product_category)
+ p2 = enterprise.products.create!(name: 'product two', product_category: @product_category)
+ enterprise.boxes.first.blocks << block
+ enterprise.add_admin(holder)
+
+ enterprise.blocks(true)
+ @controller.stubs(:boxes_holder).returns(enterprise)
+ login_as('designtestuser')
+
+ post :save, profile: 'testenterprise', id: block.id, block: { product_ids: [p1.id.to_s, p2.id.to_s ] }
+
+ assert_response :redirect
+
+ block.reload
+ assert_equal [p1.id, p2.id], block.product_ids
+
+ end
+
+end
diff --git a/plugins/products/test/test_helper.rb b/plugins/products/test/test_helper.rb
new file mode 100644
index 0000000..f620176
--- /dev/null
+++ b/plugins/products/test/test_helper.rb
@@ -0,0 +1,40 @@
+require 'test_helper'
+
+module Noosfero::Factory
+
+ def defaults_for_products_plugin_product_category
+ defaults_for_category
+ end
+
+ def defaults_for_products_plugin_product
+ { name: 'Product ' + factory_num_seq.to_s }
+ end
+
+ def defaults_for_products_plugin_production_cost
+ { name: 'Production cost ' + factory_num_seq.to_s }
+ end
+
+ def defaults_for_products_plugin_qualifier
+ { name: 'Qualifier ' + factory_num_seq.to_s, environment_id: 1 }
+ end
+ def defaults_for_qualifier
+ defaults_for_products_plugin_qualifier
+ end
+
+ def defaults_for_products_plugin_certifier
+ defaults_for_qualifier.merge({ name: 'Certifier ' + factory_num_seq.to_s })
+ end
+
+ def defaults_for_products_plugin_input
+ { }
+ end
+
+ def defaults_for_products_plugin_price_detail
+ { }
+ end
+
+ def defaults_for_unit
+ { singular: 'Litre', plural: 'Litres', environment_id: 1 }
+ end
+
+end
diff --git a/plugins/products/test/unit/enterprise_test.rb b/plugins/products/test/unit/enterprise_test.rb
new file mode 100644
index 0000000..583a61e
--- /dev/null
+++ b/plugins/products/test/unit/enterprise_test.rb
@@ -0,0 +1,12 @@
+require_relative '../test_helper'
+
+class EnterpriseTest < ActiveSupport::TestCase
+
+ should 'provide URL to catalog area' do
+ create_environment 'mycolivre.net'
+ enterprise = build(Enterprise, identifier: 'testprofile', environment_id: create_environment('mycolivre.net').id)
+
+ assert_equal({profile: enterprise.identifier, controller: 'products_plugin/catalog'}, enterprise.catalog_url)
+ end
+
+end
diff --git a/plugins/products/test/unit/environment_test.rb b/plugins/products/test/unit/environment_test.rb
new file mode 100644
index 0000000..f2310c2
--- /dev/null
+++ b/plugins/products/test/unit/environment_test.rb
@@ -0,0 +1,61 @@
+require_relative '../test_helper'
+
+class EnvironmentTest < ActiveSupport::TestCase
+
+ should 'has a list of units ordered by position' do
+ litre = create(Unit, singular: 'Litre', plural: 'Litres', environment: Environment.default)
+ meter = create(Unit, singular: 'Meter', plural: 'Meters', environment: Environment.default)
+ kilo = create(Unit, singular: 'Kilo', plural: 'Kilo', environment: Environment.default)
+ litre.move_to_bottom
+ assert_equal ["Meter", "Kilo", "Litre"], Environment.default.units.map(&:singular)
+ end
+
+ should 'have production costs' do
+ assert_respond_to Environment.default, :production_costs
+ end
+
+ should 'list_all_product_categories' do
+ env = fast_create(Environment)
+ create(Category, name: 'first category', environment_id: env.id)
+ cat = create(Category, name: 'second category', environment_id: env.id)
+ create(Category, name: 'child category', environment_id: env.id, parent_id: cat.id)
+ cat1 = create(ProductCategory, name: 'first product category', environment_id: env.id)
+ cat2 = create(ProductCategory, name: 'second product category', environment_id: env.id)
+ subcat = create(ProductCategory, name: 'child product category', environment_id: env.id, parent_id: cat2.id)
+
+ cats = env.product_categories
+ assert_equal 3, cats.size
+ assert cats.include?(cat1)
+ assert cats.include?(cat2)
+ assert cats.include?(subcat)
+ end
+
+ should 'have products through profiles' do
+ product_category = create ProductCategory, name: 'Products', environment_id: Environment.default.id
+ env = Environment.default
+ e1 = fast_create(Enterprise)
+ p1 = e1.products.create!(name: 'test_prod1', product_category: product_category)
+
+ assert_includes env.products, p1
+ end
+
+ should 'collect the highlighted products with image through enterprises' do
+ env = Environment.default
+ e1 = fast_create(Enterprise)
+ category = create(ProductCategory)
+ p1 = create(Product, :enterprise => e1, :name => 'test_prod1', :product_category_id => category.id)
+ products = []
+ 3.times {|n|
+ products.push(create(Product, :name => "product #{n}", :profile_id => e1.id,
+ :product_category_id => category.id, :highlighted => true,
+ :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
+ ))
+ }
+ create(Product, :name => "product 4", :profile_id => e1.id, :product_category_id => category.id, :highlighted => true)
+ create(Product, :name => "product 5", :profile_id => e1.id, :product_category_id => category.id, :image_builder => {
+ :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
+ })
+ assert_equal products, env.highlighted_products_with_image
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/catalog_helper_test.rb b/plugins/products/test/unit/products_plugin/catalog_helper_test.rb
new file mode 100644
index 0000000..3d3272b
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/catalog_helper_test.rb
@@ -0,0 +1,58 @@
+require_relative '../../test_helper'
+
+class CatalogHelperTest < ActiveSupport::TestCase
+
+ include ProductsPlugin::CatalogHelper
+ include ActionView::Helpers::TextHelper
+ include ActionView::Helpers::UrlHelper
+ include ActionView::Helpers::TagHelper
+ include ::Rails::Dom::Testing::Assertions::SelectorAssertions
+
+ def url_for(opts)
+ #{:controller => 'catalog', :action => 'index', :level => category.id}
+ "#{opts[:controller]}-#{opts[:action]}-level=#{opts[:level]}"
+ end
+
+ def new_productcategory(parent, name)
+ cat = ProductCategory.new(
+ :name => name, :environment => Environment.default, :parent => parent
+ )
+ cat if cat.save
+ end
+
+ def setup
+ @enterprise = Enterprise.create! :name => 'Test Enterprise',
+ :identifier => 'testenterprise',
+ :environment => Environment.default
+ @profile = @enterprise
+ @block = @enterprise.blocks.select{|b| b.class == ProductCategoriesBlock }[0]
+ @products = new_productcategory nil, 'Products'
+ @food = new_productcategory @products, 'Food'
+ @vegetables = new_productcategory @food, 'Vegetables'
+ @beans = new_productcategory @vegetables, 'Beans'
+ @rice = new_productcategory @vegetables, 'Rice'
+ @mineral = new_productcategory @products, 'Mineral'
+ @iron = new_productcategory @mineral, 'Iron'
+ @gold = new_productcategory @mineral, 'Gold'
+ end
+ attr_accessor :profile
+
+ should 'list product category sub-list' do
+ @enterprise.products.create!(:name => 'Gold Ring', :product_category => @gold)
+ @enterprise.products.create!(:name => 'Uncle Jon Beans', :product_category => @beans)
+ @enterprise.products.create!(:name => 'Red Rice', :product_category => @rice)
+
+ html = category_with_sub_list @products
+
+ doc = Nokogiri::HTML "#{html}"
+ assert_select doc, 'div' do |divs|
+ assert_select divs[0], "a[href=catalog-index-level=#{@products.id}]"
+ assert_select divs[0], '.count', {:text=>'3'}
+ assert_select divs[1], "a[href=catalog-index-level=#{@food.id}]"
+ assert_select divs[1], '.count', {:text=>'2'}
+ assert_select divs[2], "a[href=catalog-index-level=#{@mineral.id}]"
+ assert_select divs[2], '.count', {:text=>'1'}
+ end
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/category_test.rb b/plugins/products/test/unit/products_plugin/category_test.rb
new file mode 100644
index 0000000..de434c3
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/category_test.rb
@@ -0,0 +1,37 @@
+require_relative '../../test_helper'
+
+class ProductsPlugin::ProductCategoryTest < ActiveSupport::TestCase
+
+ def setup
+ @env = Environment.default
+ end
+
+ should 'should paginate recent-like methods' do
+ c = @env.product_categories.create!(name: 'my category')
+ assert c.recent_products.respond_to? 'total_entries'
+ end
+
+ should 'list recent products' do
+ product_category = create ProductCategory, name: 'Products', environment_id: Environment.default.id
+ ent1 = fast_create(Enterprise, identifier: 'enterprise_1', name: 'Enterprise one')
+ ent2 = fast_create(Enterprise, identifier: 'enterprise_2', name: 'Enterprise one')
+ prod1 = ent1.products.create!(name: 'test_prod1', product_category: product_category)
+ prod2 = ent2.products.create!(name: 'test_prod2', product_category: product_category)
+ assert_equal [prod2, prod1], product_category.recent_products
+ end
+
+ should 'have products through enterprises' do
+ product_category = create ProductCategory, name: 'Products', environment_id: Environment.default.id
+ ent1 = fast_create(Enterprise, identifier: 'enterprise_1', name: 'Enterprise one')
+ ent2 = fast_create(Enterprise, identifier: 'enterprise_2', name: 'Enterprise one')
+ prod1 = ent1.products.create!(name: 'test_prod1', product_category: product_category)
+ prod2 = ent2.products.create!(name: 'test_prod2', product_category: product_category)
+ assert_includes product_category.products, prod1
+ assert_includes product_category.products, prod2
+ end
+
+ should 'accept_products is true by default' do
+ assert Category.new.accept_products?
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/certifier_test.rb b/plugins/products/test/unit/products_plugin/certifier_test.rb
new file mode 100644
index 0000000..818e9c4
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/certifier_test.rb
@@ -0,0 +1,69 @@
+require_relative '../../test_helper'
+
+class CertifierTest < ActiveSupport::TestCase
+
+ should 'have link' do
+ certifier = Certifier.new
+
+ assert_equal '', certifier.link
+
+ certifier.link = 'http://noosfero.org'
+ assert_equal 'http://noosfero.org', certifier.link
+ end
+
+ should 'environment is mandatory' do
+ certifier = Certifier.new(:name => 'Certifier without environment')
+ refute certifier.valid?
+
+ certifier.environment = fast_create(Environment)
+ assert certifier.valid?
+ end
+
+ should 'belongs to environment' do
+ env_one = fast_create(Environment)
+ certifier_from_env_one = env_one.certifiers.create(:name => 'Certifier from environment one')
+
+ env_two = fast_create(Environment)
+ certifier_from_env_two = env_two.certifiers.create(:name => 'Certifier from environment two')
+
+ assert_includes env_one.certifiers, certifier_from_env_one
+ assert_not_includes env_one.certifiers, certifier_from_env_two
+ end
+
+ should 'name is mandatory' do
+ env_one = fast_create(Environment)
+ certifier = env_one.certifiers.new
+ refute certifier.valid?
+
+ certifier.name = 'Certifier name'
+ assert certifier.valid?
+ end
+
+ should 'sort by name' do
+ last = fast_create(Certifier, :name => "Zumm")
+ first = fast_create(Certifier, :name => "Atum")
+ assert_equal [first, last], Certifier.all.sort
+ end
+
+ should 'sorting is not case sensitive' do
+ first = fast_create(Certifier, :name => "Aaaa")
+ second = fast_create(Certifier, :name => "abbb")
+ last = fast_create(Certifier, :name => "Accc")
+ assert_equal [first, second, last], Certifier.all.sort
+ end
+
+ should 'discard non-ascii char when sorting' do
+ first = fast_create(Certifier, :name => "Áaaa")
+ last = fast_create(Certifier, :name => "Aáab")
+ assert_equal [first, last], Certifier.all.sort
+ end
+
+ should 'set qualifier as self-certified when destroyed' do
+ pq = mock
+ Certifier.any_instance.stubs(:product_qualifiers).returns([pq])
+ pq.expects(:update!).with(:certifier => nil)
+ cert = fast_create(Certifier)
+ cert.destroy
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/enterprise_homepage_helper_test.rb b/plugins/products/test/unit/products_plugin/enterprise_homepage_helper_test.rb
new file mode 100644
index 0000000..1363c33
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/enterprise_homepage_helper_test.rb
@@ -0,0 +1,63 @@
+require_relative '../../test_helper'
+
+class EnterpriseHomepageHelperTest < ActiveSupport::TestCase
+
+ include ProductsPlugin::EnterpriseHomepageHelper
+
+ def setup
+ @profile = mock
+ profile.stubs(:profile_image).returns('profileimage.png')
+ self.stubs(:url_for).returns('link to profile')
+ profile.stubs(:name).returns('Name of Profile')
+ profile.stubs(:url).returns('')
+ profile.stubs(:identifier).returns('name-of-profile')
+ profile.stubs(:region).returns(Region.new(:name => 'Brazil'))
+ profile.stubs(:address).returns('Address of Profile')
+ profile.stubs(:contact_email).returns('Email of Profile')
+ profile.stubs(:contact_phone).returns('Phone of Profile')
+ profile.stubs(:contact_person).returns('Profile Owner')
+ profile.stubs(:location).returns('Profile Location');
+ profile.stubs(:economic_activity).returns('Profile Economic Activity');
+ end
+ attr_reader :profile
+
+ should 'display profile info' do
+ result = display_profile_info(profile)
+ assert_match /Profile Owner/, result
+ assert_match /Email of Profile/, result
+ assert_match /Phone of Profile/, result
+ assert_match /Profile Location/, result
+ assert_match /Address of Profile/, result
+ assert_match /Profile Economic Activity/, result
+ end
+
+ should 'not display attribute if nil' do
+ profile.stubs(:contact_person).returns(nil);
+ result = display_profile_info(profile)
+ assert_no_match /Profile Owner/, result
+ end
+
+ should 'not display attribute if blank' do
+ profile.stubs(:contact_person).returns('');
+ result = display_profile_info(profile)
+ assert_no_match /Profile Owner/, result
+ end
+
+ should 'display distance' do
+ profile.stubs(:distance).returns(100.345);
+ result = display_profile_info(profile)
+ assert_match /Distance:/, result
+ assert_match /100.34/, result
+ end
+
+ should 'not display distance if nil' do
+ profile.stubs(:distance).returns(nil);
+ result = display_profile_info(profile)
+ assert_no_match /Distance:/, result
+ assert_no_match /100.34/, result
+ end
+
+ protected
+ include NoosferoTestHelper
+
+end
diff --git a/plugins/products/test/unit/products_plugin/enterprise_homepage_test.rb b/plugins/products/test/unit/products_plugin/enterprise_homepage_test.rb
new file mode 100644
index 0000000..f817410
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/enterprise_homepage_test.rb
@@ -0,0 +1,33 @@
+require_relative '../../test_helper'
+
+class EnterpriseHomepageTest < ActiveSupport::TestCase
+
+ def setup
+ @profile = create_user('testing').person
+ end
+ attr_reader :profile
+
+ should 'provide a proper short description' do
+ assert_kind_of String, EnterpriseHomepage.short_description
+ end
+
+ should 'provide a proper description' do
+ assert_kind_of String, EnterpriseHomepage.description
+ end
+
+ should 'return a valid body' do
+ e = EnterpriseHomepage.new(:name => 'sample enterprise homepage')
+ assert_not_nil e.to_html
+ end
+
+ should 'can display hits' do
+ a = EnterpriseHomepage.new(:name => 'Test article')
+ assert_equal false, a.can_display_hits?
+ end
+
+ should 'have can_display_media_panel with default true' do
+ a = EnterpriseHomepage.new
+ assert a.can_display_media_panel?
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/featured_products_block_test.rb b/plugins/products/test/unit/products_plugin/featured_products_block_test.rb
new file mode 100644
index 0000000..f1de152
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/featured_products_block_test.rb
@@ -0,0 +1,136 @@
+require_relative "../../test_helper"
+
+class FeaturedProductsBlockTest < ActiveSupport::TestCase
+ include BoxesHelper
+
+ def setup
+ @profile = fast_create(Profile)
+ @environment = Environment.default
+ @environment.boxes.create
+ @category = create ProductCategory
+ end
+ attr_reader :profile, :category
+
+ should 'refer to products' do
+ profile = fast_create(Enterprise)
+ products = []
+ 3.times {|n| products.push(create(Product, :name => "product #{n}", :profile_id => profile.id, :product_category_id => category.id)) }
+ featured_products_block = create(FeaturedProductsBlock, :product_ids => products.map(&:id))
+ assert_equal products, featured_products_block.products
+ end
+
+ should "have method products_for_selection" do
+ block = FeaturedProductsBlock.new
+ assert_respond_to block, 'products_for_selection'
+ end
+
+ should " the defaul product_ids be an empty array" do
+ block = FeaturedProductsBlock.new
+ assert_equal [], block.product_ids
+ end
+
+ should " the defaul groups_of be 3" do
+ block = FeaturedProductsBlock.new
+ assert_equal 3, block.groups_of
+ end
+
+ should 'default interval between transitions is 1000 miliseconds' do
+ block = FeaturedProductsBlock.new
+ assert_equal 1000, block.speed
+ end
+
+ should "reflect by default" do
+ block = FeaturedProductsBlock.new
+ assert_equal true, block.reflect
+ end
+
+ should 'describe itself' do
+ assert_not_equal Block.description, FeaturedProductsBlock.description
+ end
+
+ should "the groups_of variabe be a integer" do
+ block = FeaturedProductsBlock.new
+ assert_kind_of Integer, block.groups_of
+ block.groups_of = 2
+ block.save
+ block.reload
+ assert_kind_of Integer, block.groups_of
+ block.groups_of = '2'
+ block.save
+ block.reload
+ assert_kind_of Integer, block.groups_of
+ end
+
+ should "an environment block collect product automatically" do
+ block = build(FeaturedProductsBlock, )
+ block.product_ids = []
+ enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
+ 3.times {|n|
+ create(Product, :name => "product #{n}", :profile_id => enterprise.id,
+ :highlighted => true, :product_category_id => category.id,
+ :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
+ )
+ }
+ @environment.boxes.first.blocks<< block
+
+ assert_not_equal [], block.product_ids
+ end
+
+ should "an environment block collect just product with image automatically" do
+ block = build(FeaturedProductsBlock, )
+ block.product_ids = []
+ enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
+ 3.times {|n|
+ create(Product, :name => "product #{n}", :profile_id => enterprise.id, :highlighted => true, :product_category_id => category.id)
+ }
+ @environment.boxes.first.blocks<< block
+
+ assert_equal [], block.product_ids
+ end
+
+ should "an environment block collect just highlighted product automatically" do
+ block = build(FeaturedProductsBlock, )
+ block.product_ids = []
+ enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
+ 3.times {|n|
+ create(Product, :name => "product #{n}", :profile_id => enterprise.id, :product_category_id => category.id, :image_builder => {
+ :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
+ })
+ }
+ @environment.boxes.first.blocks<< block
+
+ assert_equal [], block.product_ids
+ end
+
+ should 'display feature products block' do
+ block = FeaturedProductsBlock.new
+
+ self.expects(:render).with(template: 'blocks/featured_products', locals: {block: block})
+ render_block_content(block)
+ end
+
+ should "return just highlighted products with image for selection" do
+ block = build(FeaturedProductsBlock, )
+ block.product_ids = []
+ enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
+ products = []
+ 3.times {|n|
+ products.push(create(Product, :name => "product #{n}", :profile_id => enterprise.id,
+ :highlighted => true, :product_category_id => category.id,
+ :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
+ ))
+ }
+ create(Product, :name => "product 4", :profile_id => enterprise.id, :product_category_id => category.id, :highlighted => true)
+ create(Product, :name => "product 5", :profile_id => enterprise.id, :product_category_id => category.id, :image_builder => {
+ :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
+ })
+ @environment.boxes.first.blocks<< block
+
+ products_for_selection = block.products_for_selection
+
+ products.each do |product|
+ assert_includes products_for_selection, product
+ end
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/input_test.rb b/plugins/products/test/unit/products_plugin/input_test.rb
new file mode 100644
index 0000000..ff0c0e8
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/input_test.rb
@@ -0,0 +1,190 @@
+require_relative '../../test_helper'
+
+class InputTest < ActiveSupport::TestCase
+
+ def setup
+ @product_category = create ProductCategory, name: 'Products'
+ end
+
+ attr_accessor :product_category
+
+ should 'require product_category' do
+ input = Input.new
+ input.valid?
+ assert input.errors[:product_category.to_s].present?
+
+ input.product_category = product_category
+ input.valid?
+ refute input.errors[:product_category.to_s].present?
+ end
+
+ should 'require product' do
+ product = fast_create(Product, :name => 'Computer', :product_category_id => product_category.id)
+
+ input = Input.new
+ input.valid?
+ assert input.errors[:product.to_s].present?
+
+ input.product = product
+ input.valid?
+ refute input.errors[:product.to_s].present?
+ end
+
+ should 'store inputs ordered by position' do
+ product = fast_create(Product, :product_category_id => product_category.id)
+
+ first_input = create(Input, :product => product, :product_category => product_category)
+ assert_equal 1, first_input.position
+
+ second_input = create(Input, :product => product, :product_category => product_category)
+ assert_equal 2, second_input.position
+ end
+
+ should 'move input to top of input list' do
+ product = fast_create(Product, :product_category_id => product_category.id)
+
+ first_input = create(Input, :product => product, :product_category => product_category)
+ second_input = create(Input, :product => product, :product_category => product_category)
+ last_input = create(Input, :product => product, :product_category => product_category)
+
+ assert_equal [first_input, second_input, last_input], product.inputs(true)
+
+ last_input.move_to_top
+
+ assert_equal [last_input, first_input, second_input], product.inputs(true)
+ end
+
+ should 'use name of product category' do
+ product = fast_create(Product, :product_category_id => product_category.id)
+ input = fast_create(Input, :product_id => product.id, :product_category_id => product_category.id)
+
+ assert_not_nil input.name
+ assert_equal product_category.name, input.name
+ end
+
+ should 'dont have price details when price related fields was not filled' do
+ input = Input.new
+ refute input.has_price_details?
+ end
+
+ should 'has price details if price_per_unit filled' do
+ input = build(Input, :price_per_unit => 10.0)
+ assert input.has_price_details?
+ end
+
+ should 'has price details if amount_used filled' do
+ input = build(Input, :amount_used => 10)
+ assert input.has_price_details?
+ end
+
+ should 'not have price details if only unit is filled' do
+ input = build(Input, :unit => Unit.new)
+ refute input.has_price_details?
+ end
+
+ should 'accept price_per_unit 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|
+ new_input = build(Input, :price_per_unit => input)
+ assert_equal output, new_input.price_per_unit
+ end
+ end
+
+ should 'accept amount_used in american\'s or brazilian\'s quantidade 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|
+ new_input = build(Input, :amount_used => input)
+ assert_equal output, new_input.amount_used
+ end
+ end
+
+ should 'display amount used' do
+ ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
+ product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
+
+ input = build(Input, :product => product)
+ input.amount_used = 10.45
+ assert_equal '10.45', input.formatted_amount
+ end
+
+ should 'display blank if amount_used is blank or nil or zero' do
+ input = Input.new
+ assert_equal '', input.formatted_amount
+ input.amount_used = ''
+ input.save
+
+ assert_equal '', input.formatted_amount
+ end
+
+ should 'display only integer value if decimal value is 00' do
+ ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
+ product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
+
+ input = build(Input, :product => product)
+ input.amount_used = 10.00
+ assert_equal '10', input.formatted_amount
+ end
+
+ should 'display formatted value' do
+ ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
+ product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
+
+ input = build(Input, :product => product)
+ input.price_per_unit = 1.45
+ assert_equal '1.45', input.formatted_value(:price_per_unit)
+
+ input.price_per_unit = 1.4
+ assert_equal '1.40', input.formatted_value(:price_per_unit)
+
+ input.price_per_unit = 1
+ assert_equal '1.00', input.formatted_value(:price_per_unit)
+ end
+
+ should 'has relation with unit' do
+ input = Input.new
+ assert_kind_of Unit, input.build_unit
+ end
+
+ should 'calculate cost of input' do
+ input = build(Input, :amount_used => 10, :price_per_unit => 2.00)
+ assert_equal 20.00, input.cost
+ end
+
+ should 'cost 0 if amount not defined' do
+ input = build(Input, :price_per_unit => 2.00)
+ assert_equal 0.00, input.cost
+ end
+
+ should 'cost 0 if price_per_unit is not defined' do
+ input = build(Input, :amount_used => 10)
+ assert_equal 0.00, input.cost
+ end
+
+ should 'list inputs relevants to price' do
+ product = fast_create(Product, :product_category_id => product_category.id)
+
+ i1 = create(Input, :product => product, :product_category => product_category, :relevant_to_price => true)
+
+ i2 = create(Input, :product => product, :product_category => product_category, :relevant_to_price => false)
+
+ i1.save!
+ i2.save!
+ assert_includes Input.relevant_to_price, i1
+ assert_not_includes Input.relevant_to_price, i2
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/price_detail_test.rb b/plugins/products/test/unit/products_plugin/price_detail_test.rb
new file mode 100644
index 0000000..4ea08e7
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/price_detail_test.rb
@@ -0,0 +1,92 @@
+require_relative '../../test_helper'
+
+class PriceDetailTest < ActiveSupport::TestCase
+
+ should 'have price 0 by default' do
+ p = PriceDetail.new
+
+ assert p.price.zero?
+ end
+
+ should 'return zero on price if it is blank' do
+ p = PriceDetail.new(:price => '')
+
+ assert p.price.zero?
+ end
+
+ should 'accept price 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|
+ new_price_detail = PriceDetail.new(:price => input)
+ assert_equal output, new_price_detail.price
+ end
+ end
+
+ should 'belongs to a product' do
+ p = PriceDetail.new
+
+ assert_respond_to p, :product
+ end
+
+ should 'product be mandatory' do
+ p = PriceDetail.new
+ p.valid?
+
+ assert p.errors[:product_id].any?
+ end
+
+ should 'have production cost' do
+ product = fast_create(Product)
+ cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment')
+ detail = product.price_details.create(:production_cost_id => cost.id, :price => 10)
+
+ assert_equal cost, PriceDetail.find(detail.id).production_cost
+ end
+
+ should 'production cost not be mandatory' do
+ product = fast_create(Product)
+ price = PriceDetail.new
+ price.product = product
+ price.valid?
+ assert price.errors.empty?
+ end
+
+ should 'the production cost be unique on scope of product' do
+ product = fast_create(Product)
+ cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'environment')
+
+ detail1 = product.price_details.create(:production_cost_id => cost.id, :price => 10)
+ detail2 = product.price_details.build(:production_cost_id => cost.id, :price => 10)
+
+ detail2.valid?
+ assert detail2.errors[:production_cost_id].any?
+ end
+
+ should 'format values to float with 2 decimals' do
+ enterprise = fast_create(Enterprise)
+ product = fast_create(Product, :profile_id => enterprise.id)
+ 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_equal "10.00", price_detail.formatted_value(:price)
+ end
+
+ should 'have the production cost name as name' do
+ product = fast_create(Product)
+ cost = fast_create(ProductionCost, :name => 'Energy',:owner_id => Environment.default.id, :owner_type => 'environment')
+
+ detail = product.price_details.create(:production_cost_id => cost.id, :price => 10)
+
+ assert_equal 'Energy', detail.name
+ end
+
+
+end
diff --git a/plugins/products/test/unit/products_plugin/product_categories_block_test.rb b/plugins/products/test/unit/products_plugin/product_categories_block_test.rb
new file mode 100644
index 0000000..c0de6b6
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/product_categories_block_test.rb
@@ -0,0 +1,21 @@
+require_relative '../../test_helper'
+
+class ProductCategoriesBlockTest < ActiveSupport::TestCase
+ should 'have display option to show only on catalog' do
+ assert ProductCategoriesBlock::DISPLAY_OPTIONS.include?('catalog_only')
+ end
+
+ should 'set display to catalog_only by default' do
+ assert_equal 'catalog_only', ProductCategoriesBlock.new.display
+ end
+
+ should 'display block only on catalog if display is set to catalog_only' do
+ enterprise = fast_create(Enterprise)
+ box = fast_create(Box, owner_id: enterprise.id, owner_type: 'Profile')
+ block = ProductCategoriesBlock.new
+ block.box = box
+
+ refute block.visible?(params: {controller: 'any_other'})
+ assert block.visible?(params: {controller: 'products_plugin/catalog'})
+ end
+end
diff --git a/plugins/products/test/unit/products_plugin/product_category_test.rb b/plugins/products/test/unit/products_plugin/product_category_test.rb
new file mode 100644
index 0000000..69fc9d9
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/product_category_test.rb
@@ -0,0 +1,88 @@
+require_relative "../../test_helper"
+
+class ProductCategoryTest < ActiveSupport::TestCase
+
+ def test_all_products
+ c0 = Environment.default.product_categories.create!(:name => 'base_cat')
+ assert_equivalent [], c0.all_products
+
+ profile = fast_create(Enterprise)
+ p0 = profile.products.create(:name => 'product1', :product_category => c0)
+ c0.reload
+ assert_equivalent [p0], c0.all_products
+
+ c1 = Environment.default.product_categories.create!(:name => 'cat_1', :parent => c0)
+ p1 = profile.products.create(:name => 'product2', :product_category => c1)
+ c0.reload; c1.reload
+ assert_equivalent [p0, p1], c0.all_products
+ assert_equivalent [p1], c1.all_products
+ end
+
+ should 'return top level product categories for environment when no parent product category specified' do
+ env1 = Environment.create!(:name => 'test env 1')
+ env2 = Environment.create!(:name => 'test env 2')
+
+ c1 = env1.product_categories.create!(:name => 'test cat 1')
+ c2 = env2.product_categories.create!(:name => 'test cat 2')
+
+ assert_equal [c1], ProductCategory.menu_categories(nil, env1)
+ end
+
+ should 'return children of parent category' do
+ c1 = Environment.default.product_categories.create!(:name => 'test cat 1')
+ c11 = Environment.default.product_categories.create!(:name => 'test cat 11', :parent => c1)
+ c2 = Environment.default.product_categories.create!(:name => 'test cat 2')
+
+ assert_equal [c11], ProductCategory.menu_categories(c1, nil)
+ end
+
+ should 'provide a scope based on the enterprise' do
+ enterprise = fast_create(Enterprise)
+ c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
+ c2 = ProductCategory.create!(:name => 'test cat 2', :environment => Environment.default)
+ c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
+ p1 = Product.new(:name => 'product1', :product_category => c1)
+ p1.profile = enterprise
+ p1.save!
+ p3 = Product.new(:name => 'product3', :product_category => c2)
+ p3.profile = enterprise
+ p3.save!
+
+ scope = ProductCategory.by_enterprise(enterprise)
+
+ assert_equivalent [c1,c2], scope
+ end
+
+ should 'provide a scope based on the enterprise returning distinct elements' do
+ enterprise = fast_create(Enterprise)
+ c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
+ c2 = ProductCategory.create!(:name => 'test cat 2', :environment => Environment.default)
+ c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
+ p1 = Product.new(:name => 'product1', :product_category => c1)
+ p1.profile = enterprise
+ p1.save!
+ p2 = Product.new(:name => 'product2', :product_category => c1)
+ p2.profile = enterprise
+ p2.save!
+ p3 = Product.new(:name => 'product3', :product_category => c2)
+ p3.profile = enterprise
+ p3.save!
+
+ scope = ProductCategory.by_enterprise(enterprise)
+
+ assert_equivalent [c1,c2], scope
+ end
+
+ should 'provide a scope based on the environment' do
+ alt_environment = fast_create(Environment)
+ c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
+ c2 = ProductCategory.create!(:name => 'test cat 2', :environment => alt_environment)
+ c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
+
+ scope = ProductCategory.by_environment(alt_environment)
+
+ assert_equivalent [c2], scope
+ assert_equivalent [c1,c3], ProductCategory.by_environment(Environment.default)
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/product_test.rb b/plugins/products/test/unit/products_plugin/product_test.rb
new file mode 100644
index 0000000..1a32be3
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/product_test.rb
@@ -0,0 +1,551 @@
+require_relative '../../test_helper'
+
+class ProductsPlugin::ProductTest < ActiveSupport::TestCase
+
+ def setup
+ super
+ @product_category = create ProductsPlugin::ProductCategory, name: 'Products'
+ @profile = create Enterprise
+ @product = create ProductsPlugin::Product, product_category: @product_category, profile: @profile
+ end
+
+ attr_accessor :product, :profile, :product_category
+
+ should 'validate the presence of enterprise' do
+ p = ProductsPlugin::Product.new
+ assert_raise ActiveRecord::RecordInvalid do
+ p.save!
+ end
+ end
+
+ should 'return associated enterprise region' do
+ @profile.region = create Region, name: 'Salvador'
+ @profile.save!
+
+ assert_equal @profile.region, product.region
+ end
+
+ should 'display category name if name is nil' do
+ product.update name: nil
+ assert_equal product_category.name, product.name
+ end
+
+ should 'display category name if name is blank' do
+ product.update name: ''
+ assert_equal product_category.name, product.name
+ end
+
+ should 'set nil to name if name is equal to category name' do
+ product.expects(:category_name).returns('Software').at_least_once
+ product.name = 'Software'
+ product.save
+ assert_equal 'Software', product.name
+ assert_equal nil, product[:name]
+ end
+
+ should 'list recent products' do
+ enterprise = create(Enterprise, name: "My enterprise", identifier: 'my-enterprise')
+ ProductsPlugin::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], ProductsPlugin::Product.recent
+ end
+
+ should 'list recent products with limit' do
+ enterprise = create(Enterprise, name: "My enterprise", identifier: 'my-enterprise')
+ ProductsPlugin::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], ProductsPlugin::Product.recent(2)
+ end
+
+ should 'save image on create product' do
+ assert_difference 'Product.count' do
+ p = create(ProductsPlugin::Product, name: 'test product1', profile: profile, 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
+ profile.update lat: 30.0, lng: 30.0
+
+ prod = ProductsPlugin::Product.find(product.id)
+ assert_equal profile.lat, prod.lat
+ assert_equal profile.lng, prod.lng
+ end
+
+ should 'provide url' do
+ enterprise = Enterprise.new
+ enterprise.expects(:public_profile_url).returns({})
+
+ product.expects(:id).returns(999)
+ product.expects(:profile).returns(enterprise)
+ assert_equal({controller: 'products_plugin/page', action: 'show', id: 999}, product.url)
+ end
+
+ should 'respond to public? as its enterprise public?' do
+ e1 = create(Enterprise, name: 'test ent 1', identifier: 'test_ent1')
+ p1 = create(ProductsPlugin::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.update 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.update discount: input
+ assert_equal output, product.discount
+ end
+ end
+
+ should 'strip name with malformed HTML when sanitize' do
+ product.name = ""
+ product.valid?
+
+ assert_equal @product_category.name, product.name
+ end
+
+ should 'not save without category' do
+ product = build(ProductsPlugin::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(ProductsPlugin::Product, name: 'Invalid category product', product_category: category)
+ end
+ end
+
+ should 'format values to float with 2 decimals' do
+ product.update 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
+ product.update price: 12.994, discount: 1.994
+
+ assert_equal 11.00, product.price_with_discount
+ end
+
+ should 'calculate price without discount' do
+ product.update price: 12.994, discount: 0
+
+ assert_equal product.price, product.price_with_discount
+ end
+
+ should 'have default image' do
+ assert_equal '/images/icons-app/product-default-pic-thumb.png', product.default_image
+ end
+
+ should 'have inputs' do
+ assert_respond_to product, :inputs
+ end
+
+ should 'return empty array if has no input' do
+ assert product.inputs.empty?
+ end
+
+ should 'return product inputs' do
+ input = create(ProductsPlugin::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
+ input = create(ProductsPlugin::Input, product_id: product.id, product_category_id: @product_category.id)
+
+ services_category = create(ProductsPlugin::ProductCategory, name: 'Services')
+ input2 = create(ProductsPlugin::Input, product_id: product.id, product_category_id: services_category.id)
+
+ assert_difference 'ProductsPlugin::Input.count', -2 do
+ product.destroy
+ end
+ end
+
+ should 'test if name is blank' do
+ assert ProductsPlugin::Product.new.name_is_blank?
+ end
+
+ should 'has basic info if filled unit, price or discount' do
+ product = ProductsPlugin::Product.new
+ refute product.has_basic_info?
+
+ product = build(ProductsPlugin::Product, unit: Unit.new)
+ assert product.has_basic_info?
+
+ product = build(ProductsPlugin::Product, price: 1)
+ assert product.has_basic_info?
+
+ product = build(ProductsPlugin::Product, discount: 1)
+ assert product.has_basic_info?
+ end
+
+ should 'destroy all qualifiers when save qualifiers list' do
+ product.product_qualifiers.create(qualifier: create(ProductsPlugin::Qualifier), certifier: create(ProductsPlugin::Certifier))
+ product.product_qualifiers.create(qualifier: create(ProductsPlugin::Qualifier), certifier: create(ProductsPlugin::Certifier))
+ product.product_qualifiers.create(qualifier: create(ProductsPlugin::Qualifier), certifier: create(ProductsPlugin::Certifier))
+
+ assert_equal 3, product.qualifiers.count
+
+ product.qualifiers_list = [[create(ProductsPlugin::Qualifier).id, create(ProductsPlugin::Certifier).id]]
+
+ assert_equal 1, product.qualifiers.count
+ end
+
+ should 'save order of inputs' do
+ first = create(ProductsPlugin::Input, product: product, product_category: create(ProductsPlugin::ProductCategory))
+ second = create(ProductsPlugin::Input, product: product, product_category: create(ProductsPlugin::ProductCategory))
+ third = create(ProductsPlugin::Input, product: product, product_category: create(ProductsPlugin::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(ProductsPlugin::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 = ProductsPlugin::Product.new
+ assert_kind_of Unit, product.build_unit
+ end
+
+ should 'respond to price details' do
+ product = ProductsPlugin::Product.new
+ assert_respond_to product, :price_details
+ end
+
+ should 'return total value of inputs' do
+ first = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::ProductCategory).id, price_per_unit: 20.0, amount_used: 2)
+ second = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::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
+ first_relevant = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::ProductCategory).id, price_per_unit: 20.0, amount_used: 2)
+ second_relevant = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::ProductCategory).id, price_per_unit: 10.0, amount_used: 1)
+ not_relevant = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::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
+ assert product.inputs_cost.zero?
+ end
+
+ should 'know if price is described' do
+ product.update price: 30.0
+
+ first = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::ProductCategory).id, price_per_unit: 20.0, amount_used: 1)
+ refute Product.find(product.id).price_described?
+
+ second = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::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
+ assert_equal false, product.price_described?
+ end
+
+ should 'create price details' do
+ cost = create(ProductsPlugin::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, ProductsPlugin::Product.find(product.id).price_details.size
+ end
+
+ should 'update price of a cost on price details' do
+ cost = create(ProductsPlugin::ProductionCost, owner_id: Environment.default.id, owner_type: 'Environment')
+ cost2 = create(ProductsPlugin::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
+ cost = create(ProductsPlugin::ProductionCost, owner_id: Environment.default.id, owner_type: 'Environment')
+ price_detail = product.price_details.create(production_cost_id: cost.id, price: 10)
+
+ assert_difference 'ProductsPlugin::PriceDetail.count', -1 do
+ product.destroy
+ end
+ end
+
+ should 'have production costs' do
+ cost = create(ProductsPlugin::ProductionCost, owner_id: Environment.default.id, owner_type: 'Environment')
+ product.price_details.create(production_cost_id: cost.id, price: 10)
+ assert_equal [cost], ProductsPlugin::Product.find(product.id).production_costs
+ end
+
+ should 'return production costs from enterprise and environment' do
+ ent_production_cost = create(ProductsPlugin::ProductionCost, owner_id: profile.id, owner_type: 'Profile')
+ env_production_cost = create(ProductsPlugin::ProductionCost, owner_id: profile.environment_id, owner_type: 'Environment')
+
+ assert_equal [env_production_cost, ent_production_cost], product.available_production_costs
+ end
+
+ should 'return all production costs' do
+ env_production_cost = create(ProductsPlugin::ProductionCost, owner_id: profile.environment_id, owner_type: 'Environment')
+ ent_production_cost = create(ProductsPlugin::ProductionCost, owner_id: profile.id, owner_type: 'Profile')
+ create ProductsPlugin::PriceDetail, product: product, production_cost: env_production_cost
+ assert_equal [env_production_cost, ent_production_cost], product.available_production_costs
+ end
+
+ should 'return total value of production costs' do
+ env_production_cost = create(ProductsPlugin::ProductionCost, owner_id: profile.environment_id, owner_type: 'Environment')
+ price_detail = create(ProductsPlugin::PriceDetail, product: product, production_cost: env_production_cost, price: 10)
+
+ input = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::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
+ input = create(ProductsPlugin::Input, product_id: product.id, product_category_id: create(ProductsPlugin::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
+ assert product.total_production_cost.zero?
+ end
+
+ should 'format inputs cost values to float with 2 decimals' do
+ first = create ProductsPlugin::Input, product_id: product.id, product_category: create(ProductsPlugin::ProductCategory), price_per_unit: 20.0, amount_used: 2
+ second = create ProductsPlugin::Input, product_id: product.id, product_category: create(ProductsPlugin::ProductCategory), 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, ProductsPlugin::Product.new.price_description_percentage
+ end
+
+ should 'return 0 on price_description_percentage if price is 0' do
+ product.update price: 0
+
+ assert_equal 0, product.price_description_percentage
+ end
+
+ should 'return 0 on price_description_percentage if price is not defined' do
+ assert_equal 0, product.price_description_percentage
+ end
+
+ should 'return 0 on price_description_percentage if total_production_cost is 0' do
+ product.update price: 50
+
+ assert_equal 0, product.price_description_percentage
+ end
+
+ should 'return solidarity percentage from inputs' do
+ prod = create(ProductsPlugin::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 = create(ProductsPlugin::Product, name: 'test product2', 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 = create(ProductsPlugin::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.any_instance.expects(:region)
+ Enterprise.any_instance.expects(:region_id)
+ product.region
+ product.region_id
+ end
+
+ should 'delegate environment info to enterprise' do
+ Enterprise.any_instance.expects(:environment)
+ Enterprise.any_instance.expects(:environment_id)
+ product.environment
+ product.environment_id
+ end
+
+ should 'return more recent products' do
+ Product.destroy_all
+
+ prod1 = create(ProductsPlugin::Product, name: 'Damaged LP', profile_id: @profile.id, product_category_id: @product_category.id)
+ prod2 = create(ProductsPlugin::Product, name: 'Damaged CD', profile_id: @profile.id, product_category_id: @product_category.id)
+ prod3 = create(ProductsPlugin::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], ProductsPlugin::Product.more_recent
+ end
+
+ should 'return products from a category' do
+ pc1 = ProductsPlugin::ProductCategory.create!(name: 'PC1', environment: Environment.default)
+ pc2 = ProductsPlugin::ProductCategory.create!(name: 'PC2', environment: Environment.default)
+ pc3 = ProductsPlugin::ProductCategory.create!(name: 'PC3', environment: Environment.default, parent: pc1)
+ p1 = create(ProductsPlugin::Product, profile: profile, product_category: pc1)
+ p2 = create(ProductsPlugin::Product, profile: profile, product_category: pc1)
+ p3 = create(ProductsPlugin::Product, profile: profile, product_category: pc2)
+ p4 = create(ProductsPlugin::Product, profile: profile, product_category: pc3)
+
+ products = ProductsPlugin::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
+ ProductsPlugin::Product.from_category(nil)
+ end
+ end
+
+ should 'return from_category scope untouched if passed nil' do
+ enterprise = create(Enterprise)
+ p1 = create(ProductsPlugin::Product, profile_id: enterprise.id, product_category: product_category)
+ p2 = create(ProductsPlugin::Product, profile_id: enterprise.id, product_category: product_category)
+ p3 = create(ProductsPlugin::Product, profile_id: enterprise.id, product_category: product_category)
+
+ 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 = create(Enterprise, public_profile: true , visible: true)
+ p1 = create(ProductsPlugin::Product, profile_id: e1.id, product_category: product_category)
+ e1.affiliate(admin, Profile::Roles.admin(env.id))
+ e1.affiliate(person, Profile::Roles.member(env.id))
+
+ e2 = create(Enterprise, public_profile: true , visible: true)
+ p2 = create(ProductsPlugin::Product, profile_id: e2.id, product_category: product_category)
+ e3 = create(Enterprise, public_profile: false, visible: true)
+ p3 = create(ProductsPlugin::Product, profile_id: e3.id, product_category: product_category)
+
+ e4 = create(Enterprise, public_profile: false, visible: true)
+ p4 = create(ProductsPlugin::Product, profile_id: e4.id, product_category: product_category)
+ e4.affiliate(admin, Profile::Roles.admin(env.id))
+ e4.affiliate(person, Profile::Roles.member(env.id))
+
+ e5 = create(Enterprise, public_profile: true, visible: false)
+ p5 = create(ProductsPlugin::Product, profile_id: e5.id, product_category: product_category)
+ e5.affiliate(admin, Profile::Roles.admin(env.id))
+ e5.affiliate(person, Profile::Roles.member(env.id))
+
+ e6 = create(Enterprise, enabled: false, visible: true)
+ p6 = create(ProductsPlugin::Product, profile_id: e6.id, product_category: product_category)
+ e6.affiliate(admin, Profile::Roles.admin(env.id))
+
+ e7 = create(Enterprise, public_profile: false, visible: false)
+ p7 = create(ProductsPlugin::Product, profile_id: e7.id, product_category: product_category)
+
+ Environment.default.add_admin(env_admin)
+
+ products_person = ProductsPlugin::Product.visible_for_person(person)
+ products_admin = ProductsPlugin::Product.visible_for_person(admin)
+ products_env_admin = ProductsPlugin::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
diff --git a/plugins/products/test/unit/products_plugin/production_cost_test.rb b/plugins/products/test/unit/products_plugin/production_cost_test.rb
new file mode 100644
index 0000000..e063409
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/production_cost_test.rb
@@ -0,0 +1,102 @@
+require_relative "../../test_helper"
+
+class ProductionCostTest < ActiveSupport::TestCase
+
+ should 'have name' do
+ p = ProductionCost.new
+ p.valid?
+ assert p.errors[:name.to_s].present?
+
+ p.name = 'Taxes'
+ p.valid?
+ refute p.errors[:name.to_s].present?
+ end
+
+ should 'not validates name if it is blank' do
+ p = ProductionCost.new
+
+ p.valid?
+ assert_equal 1, p.errors['name'].to_a.count
+ end
+
+ should 'not have a too long name' do
+ p = ProductionCost.new
+
+ p.name = 'a'*40
+ p.valid?
+ assert p.errors[:name.to_s].present?
+
+ p.name = 'a'*30
+ p.valid?
+ refute p.errors[:name.to_s].present?
+ end
+
+ should 'not have duplicated name on same environment' do
+ cost = create(ProductionCost, :name => 'Taxes', :owner => Environment.default)
+
+ invalid_cost = build(ProductionCost, :name => 'Taxes', :owner => Environment.default)
+ invalid_cost.valid?
+
+ assert invalid_cost.errors[:name.to_s].present?
+ end
+
+ should 'not have duplicated name on same enterprise' do
+ enterprise = fast_create(Enterprise)
+ cost = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
+
+ invalid_cost = build(ProductionCost, :name => 'Taxes', :owner => enterprise)
+ invalid_cost.valid?
+
+ assert invalid_cost.errors[:name.to_s].present?
+ end
+
+ should 'not allow same name on enterprise if already has on environment' do
+ enterprise = fast_create(Enterprise)
+
+ cost1 = create(ProductionCost, :name => 'Taxes', :owner => Environment.default)
+ cost2 = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
+
+ cost2.valid?
+
+ refute cost2.errors[:name.to_s].present?
+ end
+
+ should 'allow duplicated name on different enterprises' do
+ enterprise = fast_create(Enterprise)
+ enterprise2 = fast_create(Enterprise)
+
+ cost1 = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
+ cost2 = build(ProductionCost, :name => 'Taxes', :owner => enterprise2)
+
+ cost2.valid?
+
+ refute cost2.errors[:name.to_s].present?
+ end
+
+ should 'be associated to an environment as owner' do
+ p = ProductionCost.new
+ p.valid?
+ assert p.errors[:owner.to_s].present?
+
+ p.owner = Environment.default
+ p.valid?
+ refute p.errors[:owner.to_s].present?
+ end
+
+ should 'be associated to an enterprise as owner' do
+ enterprise = fast_create(Enterprise)
+ p = ProductionCost.new
+ p.valid?
+ assert p.errors[:owner.to_s].present?
+
+ p.owner = enterprise
+ p.valid?
+ refute p.errors[:owner.to_s].present?
+ end
+
+ should 'create a production cost on an enterprise' do
+ enterprise = fast_create(Enterprise)
+ create(ProductionCost, :name => 'Energy', :owner => enterprise)
+ assert_equal ['Energy'], enterprise.production_costs.map(&:name)
+ end
+end
diff --git a/plugins/products/test/unit/products_plugin/products_block_test.rb b/plugins/products/test/unit/products_plugin/products_block_test.rb
new file mode 100644
index 0000000..3bb0a0d
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/products_block_test.rb
@@ -0,0 +1,175 @@
+require_relative '../../test_helper'
+
+class ProductsBlockTest < ActiveSupport::TestCase
+
+ def setup
+ @block = ProductsBlock.new
+ @product_category = create(ProductCategory, :name => 'Products')
+ end
+ attr_reader :block
+
+ should 'be inherit from block' do
+ assert_kind_of Block, block
+ end
+
+ should 'provide default title' do
+ assert_not_equal Block.new.default_title, ProductsBlock.new.default_title
+ end
+
+ should 'provide default description' do
+ assert_not_equal Block.description, ProductsBlock.description
+ end
+
+ should 'list 4 random products by default' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product five', :product_category => @product_category)
+
+ block.stubs(:owner).returns(enterprise)
+
+ assert_equal 4, block.products.size
+ end
+
+ should 'list all products if less than 4 by default' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
+
+ block.stubs(:owner).returns(enterprise)
+
+ assert_equal 3, block.products.size
+ end
+
+
+ should 'be able to set product_ids and have them listed' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+ p3 = create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
+ p4 = create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
+ p5 = create(Product, :enterprise => enterprise, :name => 'product five', :product_category => @product_category)
+
+ block.stubs(:owner).returns(enterprise)
+
+ block.product_ids = [p1, p3, p5].map(&:id)
+ assert_equivalent [p1, p3, p5], block.products
+ end
+
+ should 'save product_ids' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+
+ block = ProductsBlock.new
+ enterprise.boxes.first.blocks << block
+ block.product_ids = [p1.id, p2.id]
+ block.save!
+
+ assert_equal [p1.id, p2.id], ProductsBlock.find(block.id).product_ids
+ end
+
+ should 'accept strings in product_ids but store integers' do
+ block = ProductsBlock.new
+ block.product_ids = [ '1', '2']
+ assert_equal [1, 2], block.product_ids
+ end
+
+ should 'not repeat products' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+ p3 = create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
+ p4 = create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
+
+ block = ProductsBlock.new
+ enterprise.boxes.first.blocks << block
+ block.save!
+
+ 4.times do # to keep a minimal chance of false positive, its random after all
+ assert_equivalent [p1, p2, p3, p4], block.products
+ end
+ end
+end
+
+require 'boxes_helper'
+require 'block_helper'
+
+class ProductsBlockViewTest < ActionView::TestCase
+ include BoxesHelper
+
+ ActionView::Base.send :include, BlockHelper
+
+ def setup
+ @block = ProductsBlock.new
+ @product_category = create(ProductCategory, :name => 'Products')
+ end
+ attr_reader :block
+
+ should "list owner products" do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+
+ block.expects(:products).returns(enterprise.products)
+
+ content = render_block_content(block)
+
+ assert_tag_in_string content, :content => 'Products'
+
+ assert_tag_in_string content, :tag => 'li', :attributes => { :class => 'product' }, :descendant => { :tag => 'a', :content => /product one/ }
+ assert_tag_in_string content, :tag => 'li', :attributes => { :class => 'product' }, :descendant => { :tag => 'a', :content => /product two/ }
+ end
+
+ should 'display the default minor image if thumbnails were not processed' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')})
+
+ block.expects(:products).returns(enterprise.products)
+ ActionView::Base.any_instance.stubs(:block_title).returns("")
+
+ content = render_block_content(block)
+
+ assert_tag_in_string content, :tag => 'a', :attributes => { :style => /image-loading-minor.png/ }
+ end
+
+ should 'display the thumbnail image if thumbnails were processed' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')})
+
+ process_delayed_job_queue
+ block.expects(:products).returns(enterprise.products.reload)
+ ActionView::Base.any_instance.stubs(:block_title).returns("")
+
+ content = render_block_content(block)
+ assert_tag_in_string content, :tag => 'a', :attributes => { :style => /rails_minor.png/ }
+ end
+
+ should 'point to all products in footer' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+
+ block.stubs(:owner).returns(enterprise)
+
+ footer = render_block_footer(block)
+
+ assert_tag_in_string footer, :tag => 'a', :attributes => { :href => /profile\/testenterprise\/plugin\/products\/catalog$/ }, :content => 'View all products'
+ end
+
+ should 'generate footer when enterprise has own hostname' do
+ enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
+ enterprise.domains << Domain.new(:name => 'sometest.com'); enterprise.save!
+ create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
+ create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
+
+ block.stubs(:owner).returns(enterprise)
+
+ footer = render_block_footer(block)
+
+ assert_tag_in_string footer, :tag => 'a', :attributes => { :href => /profile\/testenterprise\/plugin\/products\/catalog$/ }, :content => 'View all products'
+ end
+end
diff --git a/plugins/products/test/unit/products_plugin/products_helper_test.rb b/plugins/products/test/unit/products_plugin/products_helper_test.rb
new file mode 100644
index 0000000..85eb4ec
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/products_helper_test.rb
@@ -0,0 +1,184 @@
+require_relative "../../test_helper"
+
+class ProductsHelperTest < ActionView::TestCase
+
+ include ProductsPlugin::ProductsHelper
+ include ContentViewerHelper
+ include ArticleHelper
+ include ActionView::Helpers::AssetTagHelper
+ include ApplicationHelper
+
+ def setup
+ stubs(:show_date).returns('')
+ @environment = Environment.default
+ @profile = create_user('blog_helper_test').person
+ @category = create ProductCategory, name: 'Category 1', environment_id: @environment.id
+ end
+
+ attr_accessor :category
+
+ should 'display select for categories' do
+ create(ProductCategory, name: 'Category 2.1', environment_id: @environment.id, parent_id: category.id)
+ create(ProductCategory, name: 'Category 2.2', environment_id: @environment.id, parent_id: category.id)
+
+ assert_tag_in_string select_for_categories(category.children(true), 1), tag: 'select', attributes: {id: 'category_id'}
+ end
+
+ include ActionView::Helpers::NumberHelper
+ should 'format price to environment currency' do
+ @environment.currency_unit = "R$"
+ @environment.currency_separator = ","
+ @environment.currency_delimiter = "."
+ @environment.save
+ assert_equal 'R$ 10,00', float_to_currency(10.0)
+ end
+
+ should 'not display link to edit product when user does not have permission' do
+ user = mock
+ user.expects(:has_permission?).with(anything, anything).returns(false)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+ assert_equal '', edit_product_link_to_remote(product, 'field', 'link to edit')
+ end
+
+ should 'display link to edit product when user has permission' do
+ user = User.new(:email => 'display-link@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(true)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+
+ expects(:link_to_remote).with('link to edit', {update: "product-name", loading: "loading_for_button('#link-edit-product-name')", url: {controller: 'products_plugin/page', action: 'edit', id: product.id, field: 'name'}, method: :get}, anything).returns('LINK')
+
+ assert_equal 'LINK', edit_product_link_to_remote(product, 'name', 'link to edit')
+ end
+
+ should 'not display link to edit product category when user does not have permission' do
+ user = User.new(:email => 'not-display-link@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(false)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+ assert_equal '', edit_link('link to edit category', { action: 'edit_category', id: product.id })
+ end
+
+ should 'display link to edit product category when user has permission' do
+ user = User.new(:email => 'display-link@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(true)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+
+ expects(:link_to).with('link to edit category', { action: 'edit_category', id: product.id }, {} ).returns('LINK')
+
+ assert_equal 'LINK', edit_link('link to edit category', { action: 'edit_category', id: product.id })
+ end
+
+ should 'not display ui_button to edit product when user does not have permission' do
+ user = User.new(:email => 'not-display-uibutton@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(false)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+ assert_equal '', edit_ui_button(product, 'field', 'link to edit')
+ end
+
+ should 'display ui_button_to_remote to edit product when user has permission' do
+ user = User.new(:email => 'display-uibuttontoremote@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(true)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+
+ expects(:ui_button_to_remote).with('link to edit', {update: "product-info", url: {controller: 'products_plugin/page', action: 'edit', id: product.id, field: 'info'}, complete: "jQuery('#edit-product-button-ui-info').hide()", method: :get, loading: "loading_for_button('#edit-product-remote-button-ui-info')", }, id: 'edit-product-remote-button-ui-info').returns('LINK')
+
+ assert_equal 'LINK', edit_product_ui_button_to_remote(product, 'info', 'link to edit')
+ end
+
+
+ should 'display ui_button to edit product when user has permission' do
+ user = User.new(:email => 'display-uibutton@email.invalid.com')
+ user.expects(:has_permission?).with(anything, anything).returns(true)
+ @controller = mock
+ @controller.expects(:user).returns(user).at_least_once
+ @controller.expects(:profile).returns(mock)
+ product = fast_create(Product, product_category_id: category.id)
+
+ expects(:ui_button).with('link to edit', { action: 'add_input', id: product.id }, {}).returns('LINK')
+
+ assert_equal 'LINK', edit_ui_button('link to edit', {action: 'add_input', id: product.id})
+ end
+
+ should 'show unit on label of amount selection' do
+ input = build(Input)
+ input.expects(:product).returns(build(Product, unit: Unit.new(singular: 'Meter')))
+ assert_equal 'Amount used by meter of this product or service', label_amount_used(input)
+ end
+
+ should 'not show unit on label of amount selection if product has no unit selected' do
+ input = build(Input)
+ input.expects(:product).returns(Product.new)
+ assert_equal 'Amount used in this product or service', label_amount_used(input)
+ end
+
+ should 'sort qualifiers by name' do
+ fast_create(Qualifier, name: 'Organic')
+ fast_create(Qualifier, name: 'Non Organic')
+ result = qualifiers_for_select
+ assert_equal ["Select...", "Non Organic", "Organic"], result.map{|i| i[0]}
+ end
+
+ should 'sort certifiers by name' do
+ qualifier = fast_create(Qualifier, name: 'Organic')
+ fbes = fast_create(Certifier, name: 'FBES')
+ colivre = fast_create(Certifier, name: 'Colivre')
+ create(QualifierCertifier, qualifier: qualifier, certifier: colivre)
+ create(QualifierCertifier, qualifier: qualifier, certifier: fbes)
+
+ result = certifiers_for_select(qualifier)
+ assert_equal ["Self declared", "Colivre", "FBES"], result.map{|i| i[0]}
+ end
+
+ should 'list qualifiers and certifiers of a product' do
+ product = fast_create(Product)
+ qualifier = fast_create(Qualifier)
+ certifier = fast_create(Certifier)
+ create(ProductQualifier, product: product, qualifier: qualifier, certifier: certifier)
+ assert_match /✔ Qualifier \d+ certified by Certifier \d+/, display_qualifiers(product)
+ end
+
+ should 'product survive to a Qualifier deletation' do
+ product = fast_create(Product)
+ qualifier = fast_create(Qualifier)
+ certifier = fast_create(Certifier)
+ create(ProductQualifier, product: product, qualifier: qualifier, certifier: certifier)
+ qualifier.destroy
+ assert_nothing_raised do
+ assert_no_match /✔ Qualifier \d+ certified by Certifier \d+/, display_qualifiers(product)
+ end
+ end
+
+ should 'delete product Qualifier self-declared when Certifier is deleted' do
+ product = fast_create(Product)
+ qualifier = fast_create(Qualifier)
+ certifier = fast_create(Certifier)
+ create(ProductQualifier, product: product, qualifier: qualifier, certifier: certifier)
+ certifier.destroy
+ assert_nothing_raised do
+ result = display_qualifiers(product)
+ assert_match /✔ Qualifier \d+ \(Self declared\)/, result
+ assert_no_match /certified by Certifier \d+/, result
+ end
+ end
+
+ protected
+ include NoosferoTestHelper
+ include ActionView::Helpers::TextHelper
+end
diff --git a/plugins/products/test/unit/products_plugin/qualifier_certifier_test.rb b/plugins/products/test/unit/products_plugin/qualifier_certifier_test.rb
new file mode 100644
index 0000000..656395a
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/qualifier_certifier_test.rb
@@ -0,0 +1,19 @@
+require_relative "../../test_helper"
+
+class QualifierCertifierTest < ActiveSupport::TestCase
+
+ should 'connect certifiers and qualifiers' do
+ env_one = fast_create(Environment)
+ qualifier = env_one.qualifiers.create(:name => 'Qualifier')
+ certifier = env_one.certifiers.create(:name => 'Certifier')
+
+ QualifierCertifier.new.tap do |qc|
+ qc.qualifier = qualifier
+ qc.certifier = certifier
+ end.save!
+
+ assert_includes certifier.qualifiers, qualifier
+ assert_includes qualifier.certifiers, certifier
+ end
+
+end
diff --git a/plugins/products/test/unit/products_plugin/qualifier_test.rb b/plugins/products/test/unit/products_plugin/qualifier_test.rb
new file mode 100644
index 0000000..f593ab6
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/qualifier_test.rb
@@ -0,0 +1,63 @@
+require_relative "../../test_helper"
+
+class QualifierTest < ActiveSupport::TestCase
+
+ should 'environment is mandatory' do
+ qualifier = Qualifier.new(:name => 'Qualifier without environment')
+ refute qualifier.valid?
+
+ qualifier.environment = fast_create(Environment)
+ assert qualifier.valid?
+ end
+
+ should 'belongs to environment' do
+ env_one = fast_create(Environment)
+ qualifier_from_env_one = env_one.qualifiers.create(:name => 'Qualifier from environment one')
+
+ env_two = fast_create(Environment)
+ qualifier_from_env_two = env_two.qualifiers.create(:name => 'Qualifier from environment two')
+
+ assert_includes env_one.qualifiers, qualifier_from_env_one
+ assert_not_includes env_one.qualifiers, qualifier_from_env_two
+ end
+
+ should 'name is mandatory' do
+ env_one = fast_create(Environment)
+ qualifier = env_one.qualifiers.build
+ refute qualifier.valid?
+
+ qualifier.name = 'Qualifier name'
+ assert qualifier.valid?
+ end
+
+ should 'sort by name' do
+ last = fast_create(Qualifier, :name => "Zumm")
+ first = fast_create(Qualifier, :name => "Atum")
+ assert_equal [first, last], Qualifier.all.sort
+ end
+
+ should 'sorting is not case sensitive' do
+ first = fast_create(Qualifier, :name => "Aaaa")
+ second = fast_create(Qualifier, :name => "abbb")
+ last = fast_create(Qualifier, :name => "Accc")
+ assert_equal [first, second, last], Qualifier.all.sort
+ end
+
+ should 'discard non-ascii char when sorting' do
+ first = fast_create(Qualifier, :name => "Áaaa")
+ last = fast_create(Qualifier, :name => "Aáab")
+ assert_equal [first, last], Qualifier.all.sort
+ end
+
+ should 'clean all ProductQualifier when destroy a Qualifier' do
+ product1 = fast_create(Product)
+ product2 = fast_create(Product)
+ qualifier = fast_create(Qualifier, :name => 'Free Software')
+ certifier = fast_create(Certifier, :name => 'FSF')
+ ProductQualifier.create!(:product => product1, :qualifier => qualifier, :certifier => certifier)
+ ProductQualifier.create!(:product => product2, :qualifier => qualifier, :certifier => certifier)
+ assert_equal [['Free Software', 'FSF']], product1.product_qualifiers.map{|i| [i.qualifier.name, i.certifier.name]}
+ Qualifier.destroy_all
+ assert_equal [], product1.product_qualifiers(true)
+ end
+end
diff --git a/plugins/products/test/unit/products_plugin/unit_test.rb b/plugins/products/test/unit/products_plugin/unit_test.rb
new file mode 100644
index 0000000..309c30a
--- /dev/null
+++ b/plugins/products/test/unit/products_plugin/unit_test.rb
@@ -0,0 +1,40 @@
+require_relative "../../test_helper"
+
+class UnitTest < ActiveSupport::TestCase
+
+ should 'require singular name' do
+ unit = Unit.new; unit.valid?
+ assert_match /can't be blank/, unit.errors["singular"].first
+ end
+
+ should 'require plural name' do
+ unit = Unit.new; unit.valid?
+ assert_match /can't be blank/, unit.errors["plural"].first
+ end
+
+ should 'belongs and require an environment' do
+ unit = Unit.new; unit.valid?
+ assert_match /can't be blank/, unit.errors["environment_id"].first
+ unit.environment = Environment.default; unit.valid?
+ assert_nil unit.errors["environment_id"].first
+ end
+
+ should 'increment position automatically' do
+ first = Unit.new(:singular => 'Litre', :plural => 'Litres').tap do |u|
+ u.environment = Environment.default
+ u.save!
+ end
+ second = Unit.new(:singular => 'Meter', :plural => 'Meters').tap do |u|
+ u.environment = Environment.default
+ u.save!
+ end
+ assert_equal 1, first.position
+ assert_equal 2, second.position
+ end
+
+ should 'has an getter and setter alias to singular field' do
+ unit = Unit.new(:name => 'Litre')
+ assert_equal 'Litre', unit.singular
+ end
+
+end
diff --git a/plugins/products/test/unit/profile_test.rb b/plugins/products/test/unit/profile_test.rb
new file mode 100644
index 0000000..b1df2ac
--- /dev/null
+++ b/plugins/products/test/unit/profile_test.rb
@@ -0,0 +1,66 @@
+require_relative '../test_helper'
+
+class ProfileTest < ActiveSupport::TestCase
+
+ def setup
+ @product_category = create ProductsPlugin::ProductCategory, name: 'Products'
+ end
+
+ should 'list product categories' do
+ subcategory = create ProductCategory, name: 'Products subcategory', parent_id: @product_category.id
+ ent = fast_create(Enterprise, name: 'test ent', identifier: 'test_ent')
+ p = create(Product, name: 'test prod', product_category: subcategory, enterprise: ent)
+
+ assert_equivalent [subcategory], ent.product_categories
+ end
+
+ should 'not create a products block for enterprise if environment do not let' do
+ env = Environment.default
+ env.disable('products_for_enterprises')
+ ent = fast_create(Enterprise, name: 'test ent', identifier: 'test_ent')
+ assert_not_includes ent.blocks.map(&:class), ProductsBlock
+ end
+
+ should 'collect the highlighted products with image' do
+ env = Environment.default
+ e1 = fast_create(Enterprise)
+ p1 = create(Product, name: 'test_prod1', product_category_id: @product_category.id, enterprise: e1)
+ products = []
+ 3.times {|n|
+ products.push(create(Product, name: "product #{n}", profile_id: e1.id,
+ highlighted: true, product_category_id: @product_category.id,
+ image_builder: { uploaded_data: fixture_file_upload('/files/rails.png', 'image/png') }
+ ))
+ }
+ create(Product, name: "product 4", profile_id: e1.id, product_category_id: @product_category.id, highlighted: true)
+ create(Product, name: "product 5", profile_id: e1.id, product_category_id: @product_category.id, image_builder: {
+ uploaded_data: fixture_file_upload('/files/rails.png', 'image/png')
+ })
+ assert_equal products, e1.highlighted_products_with_image
+ end
+
+ should 'have many inputs through products' do
+ enterprise = fast_create(Enterprise)
+ product = fast_create(Product, profile_id: enterprise.id, product_category_id: @product_category.id)
+ product.inputs << build(Input, product_category: @product_category)
+ product.inputs << build(Input, product_category: @product_category)
+
+ assert_equal product.inputs.sort, enterprise.inputs.sort
+ end
+
+ should 'have production cost' do
+ e = fast_create(Enterprise)
+ assert_respond_to e, :production_costs
+ end
+
+ should 'remove products when removing enterprise' do
+ e = fast_create(Enterprise, name: "My enterprise", identifier: 'myenterprise')
+ create(Product, enterprise: e, name: 'One product', product_category: @product_category)
+ create(Product, enterprise: e, name: 'Another product', product_category: @product_category)
+
+ assert_difference 'Product.count', -2 do
+ e.destroy
+ end
+ end
+
+end
diff --git a/plugins/products/views/blocks/footers/products.html.slim b/plugins/products/views/blocks/footers/products.html.slim
new file mode 100644
index 0000000..fca6b48
--- /dev/null
+++ b/plugins/products/views/blocks/footers/products.html.slim
@@ -0,0 +1,2 @@
+= link_to _('View all products'), block.owner.public_profile_url.merge(controller: 'products_plugin/catalog', action: 'index')
+
diff --git a/plugins/products/views/blocks/product_categories.html.erb b/plugins/products/views/blocks/product_categories.html.erb
new file mode 100644
index 0000000..3288ec0
--- /dev/null
+++ b/plugins/products/views/blocks/product_categories.html.erb
@@ -0,0 +1,19 @@
+<%
+ if @categories.nil? or @categories.length == 0
+ categories = ProductCategory.on_level(nil).order(:name)
+ else
+ categories = @categories
+ end
+%>
+
+<%= link_to _('Catalog start'), block.owner.catalog_url, :class=>'catalog-home-link' %>
+
+ <% categories.each do |category| %>
+ <%= category_with_sub_list(category) %>
+ <% end %>
+
+<% if @categories and @categories.length == 0 %>
+
+ <%= _('There are no sub-categories for %s') % @category.name %>
+
+<% end %>
diff --git a/plugins/products/views/blocks/products.html.erb b/plugins/products/views/blocks/products.html.erb
new file mode 100644
index 0000000..0cf0d9a
--- /dev/null
+++ b/plugins/products/views/blocks/products.html.erb
@@ -0,0 +1,9 @@
+<%= block_title(block.title, block.subtitle) %>
+
+
+ <% block.products.each do |product| %>
+
+ <%= link_to(product.name, product.url, :style => 'background-image:url(%s)' % product.default_image('minor')) %>
+
+ <% end %>
+
diff --git a/plugins/products/views/person_notifier/mailer/_create_product.html.erb b/plugins/products/views/person_notifier/mailer/_create_product.html.erb
new file mode 120000
index 0000000..e1169fd
--- /dev/null
+++ b/plugins/products/views/person_notifier/mailer/_create_product.html.erb
@@ -0,0 +1 @@
+../../profile/_create_product.html.erb
\ No newline at end of file
diff --git a/plugins/products/views/person_notifier/mailer/_remove_product.html.erb b/plugins/products/views/person_notifier/mailer/_remove_product.html.erb
new file mode 120000
index 0000000..49ea419
--- /dev/null
+++ b/plugins/products/views/person_notifier/mailer/_remove_product.html.erb
@@ -0,0 +1 @@
+../../profile/_remove_product.html.erb
\ No newline at end of file
diff --git a/plugins/products/views/person_notifier/mailer/_update_product.html.erb b/plugins/products/views/person_notifier/mailer/_update_product.html.erb
new file mode 120000
index 0000000..81d9f5e
--- /dev/null
+++ b/plugins/products/views/person_notifier/mailer/_update_product.html.erb
@@ -0,0 +1 @@
+../../profile/_update_product.html.erb
\ No newline at end of file
diff --git a/plugins/products/views/products_plugin/catalog/index.html.erb b/plugins/products/views/products_plugin/catalog/index.html.erb
new file mode 100644
index 0000000..3f1fab9
--- /dev/null
+++ b/plugins/products/views/products_plugin/catalog/index.html.erb
@@ -0,0 +1,130 @@
+<% extra_content = [] %>
+<% extra_content_list = [] %>
+
+
+<% if !user.nil? && ( user.is_admin?(profile.environment) || user.is_admin?(profile) ) %>
+
+ <%= button :product, _('Manage Products/Services'), controller: 'products_plugin/page' %>
+
+<% end %>
+
+
<%= _('Products/Services') %>
+
+<%= breadcrumb(@category) if params[:level] %>
+
+
+ <% @products.each do |product| %>
+ <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_exec(&content) } %>
+ <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_exec(&content) } %>
+
+ <% status = [] %>
+ <% status << 'not-available' if !product.available %>
+ <% status << 'highlighted' if product.highlighted %>
+
+
+
+
+ <% if product.highlighted? %>
+ <%= link_to image_tag(themed_path('/images/star.png'), :class => 'star', :alt => _('Highlighted product')), product_path(product) %>
+ <% end %>
+ <% if product.image %>
+
+ <%= link_to_product product, :class => 'product-big', :style => "background-image: url(#{product.default_image(:big)})" %>
+ <%= link_to content_tag(:span, _('Zoom in')), product.default_image(:big).gsub('_big',''), :class => 'zoomify-image' %>
+
+ <% else %>
+ <%= _('No image') %>
+ <% end %>
+
+
+
+ <%= link_to_product product %>
+
+
+ <% unless product.discount.blank? or product.discount == 0 %>
+
+ <%= _('from ') + price_span(product.price) %>
+ <%= _('by ') %>
+
+ <% end %>
+ <% unless product.price.blank? or product.price == 0 %>
+
+ <%= price_span product.price_with_discount, :class => "product-price #{'with-discount' unless product.discount}" %>
+ <%= _(' / ') + (product.unit ? product.unit.singular : _('unit')) %>
+
+ <% end %>
+
+
+
+ <% if product.description %>
+
+ <%= _('description') %>
+
+
+
<%= product.description %>
+
+
+ <% end %>
+
+ <% if product.price_described? %>
+
+ <%= _('price composition') %>
+
+
+
+ <% product.inputs.relevant_to_price.each do |i| %>
+
+ <% end %>
+ <% product.price_details.each do |i| %>
+
+ <% end %>
+
+
+
+ <% end %>
+
+ <% if product.inputs.count > 0 %>
+
+ <%= _('inputs and raw materials') %>
+
+
+
+ <% product.inputs.each do |i| %>
+
+ <%= _('%{amount_used} %{unit} of') % {:amount_used => i.amount_used, :unit => i.unit.singular} + ' ' if i.has_all_price_details? %>
+ <%= i.product_category.name %>
+
+ <% end %>
+
+
+
+ <% end %>
+
+ <% unless product.qualifiers.blank? %>
+
+ <%= _('qualifiers') if product.product_qualifiers.count > 0 %>
+ <%= render :partial => 'shared/product/qualifiers', :locals => {:product => product} %>
+ <% end %>
+
+ <% extra_content_list.map do |content| %>
+
+ <% end %>
+
+ <%= _('product unavailable') unless product.available %>
+
+
+ <% end %>
+
+
+<%= pagination_links @products, params: {controller: 'products_plugin/catalog', action: :index, profile: profile.identifier} %>
+
+<%= add_zoom_to_images %>
+
+
+
diff --git a/plugins/products/views/products_plugin/page/_add_input.html.erb b/plugins/products/views/products_plugin/page/_add_input.html.erb
new file mode 100644
index 0000000..9cd87d4
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_add_input.html.erb
@@ -0,0 +1,25 @@
+
+
+<%= form_for(:input,
+ :url => {:action => 'add_input', :id => @product},
+ :html => {:method => 'post', :id => 'input-category-form'}
+ ) do |f| %>
+
+ <%= _('Choose an input or raw material to this product:') %>
+
+ <%= categories_container(select_for_new_category(@categories, @level)) %>
+
+
+
+ <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
+
+ <%= ui_icon('ui-icon-alert') %>
+ <%= _('This category does not allow registration of products, select a more specific category') %>
+
+
+ <%= button :cancel, _('Cancel'), '#', :class => 'cancel-add-input' %>
+
+
+<% end %>
+
+<%= javascript_tag "add_input_stuff()" %>
diff --git a/plugins/products/views/products_plugin/page/_categories_autocomplete.html.erb b/plugins/products/views/products_plugin/page/_categories_autocomplete.html.erb
new file mode 100644
index 0000000..b7f67a1
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_categories_autocomplete.html.erb
@@ -0,0 +1,8 @@
+<%= text_field_tag 'product_category_id', '', placeholder: _('type a category for the product') %>
+
+<%= javascript_include_tag '/javascripts/product_categories.js' %>
+<%= javascript_tag do %>
+ product_categories.autocomplete.search_url = <%= url_for(controller: 'products_plugin/page', action: :search_categories).to_json %>
+ product_categories.autocomplete.select_url = <%= url_for(controller: 'products_plugin/page', action: :show_category_tree).to_json %>
+ product_categories.autocomplete.load('#product_category_id')
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_categories_for_selection.html.erb b/plugins/products/views/products_plugin/page/_categories_for_selection.html.erb
new file mode 100644
index 0000000..9d18d09
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_categories_for_selection.html.erb
@@ -0,0 +1,10 @@
+<%= select_for_categories(categories, level) %>
+
+<%= javascript_tag do %>
+ jQuery(document).ready(function() {
+ jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
+ jQuery('#selected_category_id').val(<%= @category.id rescue nil %>)
+ jQuery('#hierarchy_navigation').html(<%= hierarchy_category_navigation(@category, :make_links => true).to_json %>)
+ toggleDisabled(<%= (!!(@category && @category.accept_products?)).to_json %>, jQuery('#save_and_continue'))
+ });
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_certifiers_for_selection.html.erb b/plugins/products/views/products_plugin/page/_certifiers_for_selection.html.erb
new file mode 100644
index 0000000..99eecea
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_certifiers_for_selection.html.erb
@@ -0,0 +1,4 @@
+<%= select_certifiers(@qualifier) + remove_qualifier_button %>
+<%= javascript_tag do %>
+ jQuery('#product-qualifiers-list *').removeClass('small-loading')
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_display_category.html.erb b/plugins/products/views/products_plugin/page/_display_category.html.erb
new file mode 100644
index 0000000..3662191
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_category.html.erb
@@ -0,0 +1,4 @@
+
+
+ <%= edit_link( _('Change category'), { :action => 'edit_category', :id => @product.id}, :id => 'link-edit-product-category') %>
+
diff --git a/plugins/products/views/products_plugin/page/_display_description.html.erb b/plugins/products/views/products_plugin/page/_display_description.html.erb
new file mode 100644
index 0000000..45d6f7a
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_description.html.erb
@@ -0,0 +1,15 @@
+<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
+<% if !@product.description.blank? %>
+ <%= @product.description %>
+ <%= edit_product_button_to_remote(@product, 'description', _('Edit description'), :title => _('Edit the description of your product and give consumers more information about what you are advertising')) %>
+<% else %>
+ <%= edit_product_ui_button_to_remote(
+ @product,
+ 'description',
+ _('Add some description to your product'),
+ 'data-primary-icon' => 'ui-icon-pencil',
+ 'data-secondary-icon' => 'ui-icon-triangle-1-s',
+ :title => _('Add a description to your product and give consumers more information about what you are advertising')
+ ) %>
+ <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-description')") %>
+<% end%>
diff --git a/plugins/products/views/products_plugin/page/_display_image.html.erb b/plugins/products/views/products_plugin/page/_display_image.html.erb
new file mode 100644
index 0000000..e8e44fb
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_image.html.erb
@@ -0,0 +1,11 @@
+
+ <%= image_tag (@product.reload.default_image('big')), :class => 'product-pic' %>
+
+
+<% if @product.image %>
+ <%= link_to content_tag(:span, _('Zoom in')), @product.image.public_filename,
+ :class => 'zoomify-image' %>
+<% end %>
+<%= add_zoom_to_images %>
+
+<%= edit_product_link_to_remote(@product, 'image', _('Change image')) %>
diff --git a/plugins/products/views/products_plugin/page/_display_info.html.erb b/plugins/products/views/products_plugin/page/_display_info.html.erb
new file mode 100644
index 0000000..d7adc96
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_info.html.erb
@@ -0,0 +1,17 @@
+
+ <%= display_value(@product) %>
+ <%= display_availability(@product) %>
+ <%= display_qualifiers(@product) %>
+
+ <% if @product.has_basic_info? %>
+ <%= edit_product_button_to_remote(@product, 'info', _('Edit basic information'), :title => _('Click here to edit price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers')) %>
+ <% else %>
+ <%= edit_product_ui_button_to_remote(@product, 'info', _('Add price and other basic information'),
+ :title => _('Click here to add 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')
+ %>
+ <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-info')") %>
+ <% end%>
+
+
diff --git a/plugins/products/views/products_plugin/page/_display_input.html.erb b/plugins/products/views/products_plugin/page/_display_input.html.erb
new file mode 100644
index 0000000..a54940b
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_input.html.erb
@@ -0,0 +1,21 @@
+
+
+ <% if user && user.has_permission?('manage_products', profile) %>
+ <%= javascript_tag "input_javascript_stuff(#{input.id})" %>
+ <% end %>
diff --git a/plugins/products/views/products_plugin/page/_display_inputs.html.erb b/plugins/products/views/products_plugin/page/_display_inputs.html.erb
new file mode 100644
index 0000000..889ffe8
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_inputs.html.erb
@@ -0,0 +1,33 @@
+
+
+
+ <% if @product.inputs.empty? %>
+ <%= edit_ui_button(
+ _('Add the inputs or raw material used by this product'),
+ {action: 'add_input', id: @product.id},
+ id: 'add-input-button',
+ 'data-primary-icon' => 'ui-icon-pencil',
+ 'data-secondary-icon' => 'ui-icon-triangle-1-s',
+ title: _('Add inputs or raw materials used by this product and give more transparency to consumers about your enterprise')
+ ) %>
+ <%= javascript_tag("render_jquery_ui_buttons('add-input-button')") %>
+ <% else %>
+ <%= edit_button(:add, _('Add new input or raw material'), {action: 'add_input', id: @product.id}, id: 'add-input-button', title: _('Add new input or raw material used by this product and give more transparency to consumers about your enterprise')) %>
+ <%= content_tag('span', _('Drag the input with the mouse to change the order'), class: 'hint', style: 'display: none') %>
+ <% end %>
+
+
+
+
+
+<% if user && user.has_permission?('manage_products', profile) %>
+ <% if @product.inputs.size > 1 %>
+ <%= javascript_tag "input_javascript_ordering_stuff()" %>
+ <% end %>
+ <%= javascript_tag "display_input_stuff()" %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_display_name.html.erb b/plugins/products/views/products_plugin/page/_display_name.html.erb
new file mode 100644
index 0000000..7d61afc
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_name.html.erb
@@ -0,0 +1,13 @@
+
+
<%= @product.name_with_unit %>
+ <%= edit_product_link_to_remote(@product, 'name', _('Edit name and unit'), :title => _('Click here to edit the name of your product and the unit')) %>
+
+<%= javascript_tag do %>
+ jQuery('#display-product-category .hierarchy-category').first().html('<%=
+ escape_javascript(hierarchy_category_navigation(
+ @product.product_category,
+ :make_links => false,
+ :hide_current_category => @product.name_is_blank?)
+ )
+ %>')
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_display_price_details.html.erb b/plugins/products/views/products_plugin/page/_display_price_details.html.erb
new file mode 100644
index 0000000..47f81c6
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_display_price_details.html.erb
@@ -0,0 +1,18 @@
+
+
+
+
+
+ <%= _('Inputs:') %>
+
+ <%= float_to_currency(@product.inputs_cost) %>
+
+
+ <% @product.price_details.each do |price_detail| %>
+
+ <%= "%s:" % price_detail.name %>
+ <%= float_to_currency(price_detail.price) %>
+
+ <% end %>
+
+
diff --git a/plugins/products/views/products_plugin/page/_edit_description.html.erb b/plugins/products/views/products_plugin/page/_edit_description.html.erb
new file mode 100644
index 0000000..87399f8
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_description.html.erb
@@ -0,0 +1,14 @@
+<%= render file: 'shared/tiny_mce', locals: {mode: 'simple'} %>
+<%= remote_form_for(@product,
+ loading: "small_loading('product-description-form')",
+ update: 'product-description',
+ url: {controller: 'products_plugin/page', action: 'edit', id: @product, field: 'description'},
+ html: {id: 'product-description-form', method: 'post'}) do |f| %>
+
+ <%= labelled_form_field(_('Description:'), f.text_area(:description, rows: 15, style: 'width: 90%;', class: 'mceEditor')) %>
+ <% button_bar do %>
+ <%= submit_button :save, _('Save') %>
+ <%= cancel_edit_product_link(@product, 'description') %>
+ <% end %>
+
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_edit_image.html.erb b/plugins/products/views/products_plugin/page/_edit_image.html.erb
new file mode 100644
index 0000000..5a6bf0c
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_image.html.erb
@@ -0,0 +1,26 @@
+
+ <%= image_tag (@product.reload.default_image('thumb')), class: 'product-pic' %>
+
+
+<%= form_for(:product, url: { controller: 'products_plugin/page', action: 'edit', id: @product, field: 'image' }, html: { method: 'post', id: 'uploadForm', multipart: true}) do |f| %>
+ <%= f.fields_for :image_builder, @product.image do |i| %>
+ <%= i.file_field( :uploaded_data, { size: 10 } ) %>
+ <%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
+ <% end %>
+
+ <%= submit_button 'save', _('Save') %>
+ <%= cancel_edit_product_link(@product, 'image') %>
+<% end %>
+
+
+
+<% if errors %>
+ <%= render_dialog_error_messages 'product' %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_edit_info.html.erb b/plugins/products/views/products_plugin/page/_edit_info.html.erb
new file mode 100644
index 0000000..faeec3b
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_info.html.erb
@@ -0,0 +1,63 @@
+<% if errors %>
+ <%= render_dialog_error_messages 'product' %>
+<% end %>
+
+<%= remote_form_for(@product,
+ loading: "small_loading('product-info-form')",
+ update: 'product-info',
+ url: {controller: 'products_plugin/page', action: 'edit', id: @product, field: 'info'},
+ html: {id: 'product-info-form', method: 'post'}) do |f| %>
+
+
+
+ <%= f.label :price, _('Price (%s)') % environment.currency_unit, class: 'formlabel' %>
+ <%= f.text_field(:price, value: @product.formatted_value(:price), class: 'numbers-only') %>
+
+
+ <%= f.label :discount, _('Discount (%s)') % environment.currency_unit, class: 'formlabel' %>
+ <%= f.text_field(:discount, value: @product.formatted_value(:discount), class: 'numbers-only', title: _('If your product is on sale, fill this field with the discount value')) %>
+
+
+ <%= _('Available') %>
+ <%= labelled_radio_button( _('Yes'), 'product[available]', true, @product.available, id: 'product_available') + labelled_radio_button( _('No'), 'product[available]', false, !@product.available) %>
+
+
+ <%= f.label :highlighted, _('Highlight this product?'), class: 'formlabel' %>
+ <%= f.check_box(:highlighted) %>
+
+
+
+ <% if !environment.qualifiers.empty? %>
+
+
+ <%= _('Qualifier') %>
+ <%= _('Certifier') %>
+
+ <% @product.qualifiers.each_with_index do |qualifier, index| %>
+
+
+ <%= select_qualifiers(@product, qualifier.id) %>
+
+
+ <%= select_certifiers(qualifier, @product) + remove_qualifier_button %>
+
+
+ <% end %>
+
+ <%= button_to_function(
+ :add,
+ _('Add new qualifier'),
+ "new_qualifier_row('#product-qualifiers-list', '#{escape_javascript(CGI::escape_html(select_qualifiers(@product)))}', '#{escape_javascript(CGI::escape_html(remove_qualifier_button))}')"
+ ) %>
+ <%= hidden_field_tag "product[qualifiers_list][nil]" %>
+ <% end %>
+
+ <%= hidden_field_tag 'info-bar-update-url', @product.price_composition_bar_display_url, class: 'bar-update-url' %>
+
+ <% button_bar do %>
+ <%= submit_button :save, _('Save') %>
+ <%= cancel_edit_product_link(@product, 'info') %>
+ <% end %>
+<% end %>
+
+<%= render partial: 'shared/numbers_only_javascript' %>
diff --git a/plugins/products/views/products_plugin/page/_edit_input.html.erb b/plugins/products/views/products_plugin/page/_edit_input.html.erb
new file mode 100644
index 0000000..1079fe7
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_input.html.erb
@@ -0,0 +1,43 @@
+<%= form_for(:input, url: {controller: 'products_plugin/page', action: 'edit_input', id: @input},
+ html: {method: 'post', id: "edit-input-#{ @input.id }-form"}) do |f| %>
+
+ <%= hidden_field_tag 'input-bar-update-url', @input.product.price_composition_bar_display_url, class: 'bar-update-url' %>
+ <%= hidden_field_tag 'inputs-cost-update-url', @input.product.inputs_cost_update_url %>
+
+
+
+ <%= f.label :amount_used, label_amount_used(@input), class: 'formlabel' %>
+ <%= f.text_field(:amount_used, value: @input.formatted_amount, class: 'numbers-only amount-used') + select_unit(@input) %>
+
+
+ <%= f.label :price_per_unit, _('Price %s (%s)') % [display_price_by(@input.unit), environment.currency_unit], class: 'formlabel' %>
+ <%= f.text_field(:price_per_unit, value: @input.formatted_value(:price_per_unit), class: 'numbers-only price-per-unit') %>
+
+
+ <%= _("This input or raw material inpact on the final price of the product?") %>
+
+ <%= radio_button :input, 'relevant_to_price', true %>
+ <%= _('Yes') %>
+ <%= radio_button :input, 'relevant_to_price', false %>
+ <%= _('No') %>
+
+
+
+ <%= _('Is it from solidarity economy?') %>
+
+ <%= radio_button :input, 'is_from_solidarity_economy', true %>
+ <%= _('Yes') %>
+ <%= radio_button :input, 'is_from_solidarity_economy', false %>
+ <%= _('No') %>
+
+
+
+
+ <%= submit_button :save, _('Save'), title: _('Save changes of this input or raw material') %>
+ <%= button :cancel, _('Cancel'), '#', class: 'cancel-edit-input', id: "cancel-edit-input-#{@input.id}", title: _('Cancel changes of this input or raw material') %>
+
+
+
+<% end %>
+
+<%= javascript_tag "edit_input_stuff(#{@input.id}, '#{environment.currency_separator}')" %>
diff --git a/plugins/products/views/products_plugin/page/_edit_name.html.erb b/plugins/products/views/products_plugin/page/_edit_name.html.erb
new file mode 100644
index 0000000..410ceab
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_name.html.erb
@@ -0,0 +1,21 @@
+<%= remote_form_for(@product,
+ loading: "small_loading('product-name-form')",
+ update: 'product-name',
+ url: {controller: 'products_plugin/page', action: 'edit', id: @product, field: 'name'},
+ html: {method: 'post', id: 'product-name-form'}) do |f| %>
+ <%= f.text_field(:name, value: @product.name, class: 'name_edition') %>
+ <%= select_unit(@product) %>
+
+ <% button_bar do %>
+ <%= submit_button :save, _('Save') %>
+ <%= cancel_edit_product_link(@product, 'name') %>
+ <% end %>
+<% end %>
+
+
+
+<% if errors %>
+ <%= render_dialog_error_messages 'product' %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_edit_price_details.html.erb b/plugins/products/views/products_plugin/page/_edit_price_details.html.erb
new file mode 100644
index 0000000..16480d8
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_edit_price_details.html.erb
@@ -0,0 +1,14 @@
+<% price_details.each do |price_detail| %>
+
+ <%= select_production_cost(@product, price_detail.production_cost_id) %>
+ <%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', price_detail.formatted_value(:price), :class => 'numbers-only price-details-price', :size => 6)) %>
+
+ <%= link_to_remote(_('Remove'),
+ :update => "price-detail-#{price_detail.id}",
+ :complete => "calculateValuesForBar();",
+ data: {confirm: _('Are you sure that you want to remove this cost?')},
+ :url => { :action => 'remove_price_detail', :id => price_detail, :product => @product }) %>
+
+<% end %>
+
+<%= render :partial => 'shared/numbers_only_javascript' %>
diff --git a/plugins/products/views/products_plugin/page/_form.html.erb b/plugins/products/views/products_plugin/page/_form.html.erb
new file mode 100644
index 0000000..8639138
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_form.html.erb
@@ -0,0 +1,17 @@
+<%= error_messages_for :product %>
+
+<%= form_for :product, :html => {:multipart => true }, :url => {:action => mode} do |f| %>
+ <%= required_fields_message %>
+
+ <%= display_form_field( _('Name:'), f.text_field(:name) ) %>
+ <%= display_form_field( _('Price:'), f.text_field(:price) ) %>
+ <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10, :class => 'mceEditor') ) %>
+ <%= labelled_form_field(f.check_box(:highlighted) + _('Highlight this product'),'') %>
+ <%= f.fields_for :image_builder, @product.image do |i| %>
+ <%= file_field_or_thumbnail(_('Image:'), @product.image, i) %>
+ <% end %>
+
+ <% button_bar do %>
+ <%= submit_button('save', (mode == 'new' ? _('Create product') : _('Save changes')), :cancel => {:action => 'index'} ) %>
+ <% end %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/_input.html.erb b/plugins/products/views/products_plugin/page/_input.html.erb
new file mode 100644
index 0000000..112bf4c
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_input.html.erb
@@ -0,0 +1,3 @@
+
+<%= render 'products_plugin/page/display_input', input: input %>
+
diff --git a/plugins/products/views/products_plugin/page/_manage_product_details.html.erb b/plugins/products/views/products_plugin/page/_manage_product_details.html.erb
new file mode 100644
index 0000000..c7c84ce
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_manage_product_details.html.erb
@@ -0,0 +1,43 @@
+
+ <%= render :partial => 'manage_products/price_composition_bar' %>
+
+
+<%= form_tag({:action => 'manage_product_details'}, :method => 'post', :id => 'manage-product-details-form') do %>
+
+
+
+ <%= _('Inputs') %>
+
+ <%= float_to_currency(@product.inputs_cost) %>
+
+
+ <%= _('This value is composed by the total value of registered inputs') %>
+
+
+ <%= render :partial => 'manage_products/edit_price_details', :locals => {:price_details => @product.price_details} %>
+
+
+
+ <%= hidden_field(:product, :inputs_cost) %>
+ <%= hidden_field(:product, :price) %>
+
+ <% button_bar do %>
+ <%= submit_button :save, _('Save'), :disabled => '', :class => 'disabled' %>
+ <%= button :cancel, _('Cancel'), '#', class: 'cancel-price-details', data: {confirm: _('If you leave, you will lose all unsaved information. Are you sure you want to quit?')} %>
+ <%= button(:add, _('New cost'), '#', :id => 'add-new-cost') %>
+
+ <% end %>
+
+<% end %>
+
+
+
+
+ <%= select_production_cost(@product) %>
+ <%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', nil, :class => 'numbers-only price-details-price', :size => 6)) %>
+ <%= link_to(_('Cancel'), '#', {:class => 'cancel-new-cost'}) %>
+
+
+
+
+<%= render :partial => 'shared/numbers_only_javascript' %>
diff --git a/plugins/products/views/products_plugin/page/_price_composition_bar.html.erb b/plugins/products/views/products_plugin/page/_price_composition_bar.html.erb
new file mode 100644
index 0000000..7ec3d97
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_price_composition_bar.html.erb
@@ -0,0 +1,22 @@
+<%= javascript_tag do %>
+ var value = <%= @product.price_description_percentage %>;
+ var total_cost = <%= @product.total_production_cost %>;
+ var price = '<%= @product.formatted_value(:price) %>';
+ var described = false;
+ var currency_format = { separator : '<%= environment.currency_separator %>', delimiter : '<%= environment.currency_delimiter %>', unit : '<%= environment.currency_unit %>' };
+ if (<%= @product.price_described? %>) {
+ var described = true;
+ }
+ priceCompositionBar(value,described,total_cost,price);
+<% end %>
+
+
+
+
+
+ <%= price_composition_progressbar_text(@product) %>
+
+
+
' data-price-described-notice='<%= _("Congratulations! Now the price is open to the public") %>'>
+
+
diff --git a/plugins/products/views/products_plugin/page/_price_details_button.html.erb b/plugins/products/views/products_plugin/page/_price_details_button.html.erb
new file mode 100644
index 0000000..8ee8eaf
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_price_details_button.html.erb
@@ -0,0 +1,10 @@
+<%= edit_ui_button(
+ _('Describe here the cost of production'),
+ {:action => 'manage_product_details', :id => @product.id},
+ :id => 'manage-product-details-button',
+ 'data-primary-icon' => 'ui-icon-pencil',
+ 'data-secondary-icon' => 'ui-icon-triangle-1-s',
+ :title => _('Describe details about how the price was defined')
+) %>
+<%= javascript_tag("render_jquery_ui_buttons('manage-product-details-button')") %>
+
diff --git a/plugins/products/views/products_plugin/page/_selected_category_tree.html.erb b/plugins/products/views/products_plugin/page/_selected_category_tree.html.erb
new file mode 100644
index 0000000..120d6b5
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/_selected_category_tree.html.erb
@@ -0,0 +1,2 @@
+<%= categories_container selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true) %>
+
diff --git a/plugins/products/views/products_plugin/page/edit.html.erb b/plugins/products/views/products_plugin/page/edit.html.erb
new file mode 100644
index 0000000..d24e263
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/edit.html.erb
@@ -0,0 +1,3 @@
+ <%= _('Editing') %> <%= @product.name %>
+
+<%= render 'products_plugin/page/form', mode: 'edit' %>
diff --git a/plugins/products/views/products_plugin/page/edit_category.html.erb b/plugins/products/views/products_plugin/page/edit_category.html.erb
new file mode 100644
index 0000000..2e33e85
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/edit_category.html.erb
@@ -0,0 +1,33 @@
+
+ <%= hierarchy_category_navigation(@category, make_links: false)%>
+
+
+
+
+
<%= @product.name %>
+
+
+
+ <%= remote_form_for(@product,
+ loading: "open_loading('#{ _('loading...') }')",
+ update: "request_result_message",
+ url: {action: 'edit_category', id: @product},
+ html: {method: 'post', id: 'category_form'}) do |f| %>
+
+
<%= _('Edit category of this product:') %>
+
+ <%= render 'products_plugin/page/selected_category_tree' %>
+
+
+ <%= button(:back, _('Back to product'), action: 'show', id: @product) %>
+
+ <%= submit_button(:save, _('Save and continue'), id: 'save_and_continue') %>
+
+ <%= ui_icon('ui-icon-alert') %>
+ <%= _('This category does not allow registration of products, select a more specific category') %>
+
+
+
+
+ <% end %>
+
diff --git a/plugins/products/views/products_plugin/page/index.html.erb b/plugins/products/views/products_plugin/page/index.html.erb
new file mode 100644
index 0000000..f4c5ae4
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/index.html.erb
@@ -0,0 +1,30 @@
+ <%=_('Listing products and services') %>
+
+
+
+ <%= _('Product') %>
+ <%= _('Price') %>
+ <%= _('Actions') %>
+
+ <% if @products.empty? %>
+
+ <%= _('(no product registered yet)') %>
+
+ <% end %>
+ <% @products.each do |product| %>
+
+ <%= link_to product.name, :action => 'show', :id => product %>
+ <%= product.price %>
+
+ <%= button :delete, _('Remove'), {action: 'destroy', id: product}, data: {confirm: _('Are you sure you want to remove this product?')} %>
+
+
+ <% end %>
+
+
+<%= pagination_links @products %>
+
+<% button_bar do %>
+ <%= button :add, _('New product or service'), :action => 'new' if @profile.create_product? %>
+ <%= button :back, _('Back'), { :controller => 'profile_editor', :profile => @profile.identifier, :action => 'index' } %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/new.html.erb b/plugins/products/views/products_plugin/page/new.html.erb
new file mode 100644
index 0000000..7585ec7
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/new.html.erb
@@ -0,0 +1,30 @@
+<%= _('New product or service') %>
+
+
+
+<%= remote_form_for @product,
+ loading: "open_loading('#{ _('loading...') }')",
+ update: "request_result_message",
+ url: {action: 'new'},
+ html: {method: 'post', id: 'category_form'} do |f| %>
+
+ <%= _('Select the category of the new product or service') %>
+
+ <%= categories_container(select_for_new_category(@categories, @level)) %>
+
+
+ <%= button :back, _('Back to the product listing'), action: 'index' %>
+
+ <%= submit_button(:save, _('Save and continue'), id: 'save_and_continue') %>
+
+ <%= ui_icon('ui-icon-alert') %>
+ <%= _('This category does not allow registration of products, select a more specific category') %>
+
+
+
+
+<% end %>
+
+<%= javascript_tag do %>
+ toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, jQuery('#save_and_continue')[0])
+<% end %>
diff --git a/plugins/products/views/products_plugin/page/show.html.erb b/plugins/products/views/products_plugin/page/show.html.erb
new file mode 100644
index 0000000..b81a385
--- /dev/null
+++ b/plugins/products/views/products_plugin/page/show.html.erb
@@ -0,0 +1,74 @@
+
+ <%= render 'products_plugin/page/display_category' %>
+
+
+
+
+
+ <%= render 'products_plugin/page/display_name' %>
+
+
+
+
+ <%= render 'products_plugin/page/display_image' %>
+
+
+
+ <%= render 'products_plugin/page/display_info' %>
+
+
+
+
+
+ <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty? && !@product.price_described? ) %>
+ <% plugins_tabs = plugins_product_tabs %>
+
+
+
+
+
+ <%= render 'products_plugin/page/display_description' %>
+
+
+
+ <%= render 'products_plugin/page/display_inputs' %>
+
+
+ <% if @product.price_described? || @allowed_user %>
+
+ <%= render 'products_plugin/page/display_price_details' %>
+ <%= render 'products_plugin/page/price_details_button' %>
+
+ <% end %>
+
+ <% plugins_tabs.each do |tab| %>
+
<%= raw tab[:content] %>
+ <% end %>
+
+
+ <% end %>
+
+
+
+<% button_bar do %>
+ <%= button :back, _('Back to the product listing'), controller: 'products_plugin/catalog', action: 'index' %>
+ <%= button :delete, _('Remove product or service'), {action: 'destroy', id: @product}, class: 'requires-permission-manage_products', style: 'display:none;' %>
+<% end %>
diff --git a/plugins/products/views/products_plugin/search/products_plugin/_full_product.html.erb b/plugins/products/views/products_plugin/search/products_plugin/_full_product.html.erb
new file mode 100644
index 0000000..4b5f135
--- /dev/null
+++ b/plugins/products/views/products_plugin/search/products_plugin/_full_product.html.erb
@@ -0,0 +1,96 @@
+<% extra_content = @plugins.dispatch(:asset_product_extras, product).collect { |content| instance_exec(&content) } %>
+<% extra_properties = @plugins.dispatch(:asset_product_properties, product) %>
+
+
+
+
+
+ <% if product.image %>
+
+ <%= link_to '', product_path(product), class: "search-image-pic",
+ style: 'background-image: url(%s)'% product.default_image(:thumb) %>
+ <%= link_to content_tag(:span, _('Zoom in')), product.image.public_filename,
+ class: 'zoomify-image' %>
+
+ <% else %>
+
<%= _('No image') %>
+ <% end %>
+
+
+ <% if product.available %>
+ <% if product.price && product.price > 0 %>
+ <% has_discount = product.discount && product.discount > 0 %>
+ <% if product.price %>
+
<%=_("from") if has_discount %> <%= price_span(product.price, class: "search-product-price " + (has_discount ? 'with-discount' : '')) %>
+ <% if has_discount %>
+
<%=_("by")%> <%= price_span(product.price_with_discount, class: "search-product-price") %>
+ <% end %>
+ <% if product.unit %>
+
<%= _('/') %> <%= product.unit.name %>
+ <% end %>
+ <% end %>
+
+ <% end %>
+ <% else %>
+
<%= _('Not available') %>
+ <% end %>
+
+
+
+ <%= link_to_product product, class: 'search-result-title' %>
+
+ <%= _('Supplier') %> <%= link_to_homepage product.enterprise.name, product.enterprise %>
+
+
+ <% if product.description %>
+ <% desc_stripped = strip_tags(product.description) %>
+ <%= _('Description') %> <%= excerpt desc_stripped, desc_stripped.first(3), radius: 300 %>
+ <% end %>
+
+
+
+
+ <% if product.enterprise.region %>
+ <%= _('City') %>
+ <%= city_with_state(product.enterprise.region) %>
+ <% end %>
+
+
+ <% if product.product_qualifiers.count > 0 %>
+ <%= _('Qualifiers') %>
+ <% product.product_qualifiers.each do |pq| %>
+ <% if pq.qualifier %>
+ <%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %>
+ <% end %>
+ <% if pq.certifier %>
+ <%= _('cert. ') + pq.certifier.name + _(";") %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+
+
+
+
+ <%= safe_join(extra_content, '\n') %>
+ <% extra_properties.each do |property| %>
+ <%= ''.html_safe + property[:name] + ': ' + instance_exec(&property[:content]) %>
+ <% end %>
+
+
diff --git a/plugins/products/views/profile/_create_product.html.erb b/plugins/products/views/profile/_create_product.html.erb
new file mode 100644
index 0000000..094309f
--- /dev/null
+++ b/plugins/products/views/profile/_create_product.html.erb
@@ -0,0 +1,13 @@
+
+ <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
+
+
+
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
+
<%= time_ago_in_words activity.created_at %>
+
+
+ <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
+
+
+
+
diff --git a/plugins/products/views/profile/_remove_product.html.erb b/plugins/products/views/profile/_remove_product.html.erb
new file mode 100644
index 0000000..1fb0afa
--- /dev/null
+++ b/plugins/products/views/profile/_remove_product.html.erb
@@ -0,0 +1,12 @@
+
+
+
+
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
+
<%= time_ago_in_words activity.created_at %>
+
+
+ <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
+
+
+
+
diff --git a/plugins/products/views/profile/_update_product.html.erb b/plugins/products/views/profile/_update_product.html.erb
new file mode 100644
index 0000000..094309f
--- /dev/null
+++ b/plugins/products/views/profile/_update_product.html.erb
@@ -0,0 +1,13 @@
+
+ <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
+
+
+
<%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %>
+
<%= time_ago_in_words activity.created_at %>
+
+
+ <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
+
+
+
+
diff --git a/plugins/products/views/profile_design/products_plugin/_featured_products_block.html.erb b/plugins/products/views/profile_design/products_plugin/_featured_products_block.html.erb
new file mode 100644
index 0000000..123c1e1
--- /dev/null
+++ b/plugins/products/views/profile_design/products_plugin/_featured_products_block.html.erb
@@ -0,0 +1,8 @@
+<%= _('Featured Products') %>
+
+
<%= label_tag _('Choose some products') %>
+
<%= select_tag 'block[product_ids][]', options_for_select(@block.products_for_selection.map{|p| [p.name, p.id.to_s]}, @block.product_ids), :multiple => true %>
+
<%= labelled_form_field check_box(:block, :reflect) + _('Reflect products'), '' %>
+
<%= labelled_form_field(_('Transition speed (in seconds)'), select('block', 'speed', (1..10).to_a.collect{|i| [i, i*1000] })) %>
+
<%= labelled_form_field(_('In groups of'), select('block', 'groups_of', (1..10).to_a)) %>
+
diff --git a/plugins/products/views/profile_design/products_plugin/_products_block.html.erb b/plugins/products/views/profile_design/products_plugin/_products_block.html.erb
new file mode 100644
index 0000000..dfaedd3
--- /dev/null
+++ b/plugins/products/views/profile_design/products_plugin/_products_block.html.erb
@@ -0,0 +1,13 @@
+
+
+
+
+<%= _('Select the products that must be shown.') %>
+
+
+
+<% for product in @block.owner.products %>
+ <%= check_box_tag("block[product_ids][]", product.id, (!@block.product_ids.blank? && @block.product_ids.include?(product.id)), :id => "block_product_ids_#{product.id}" ) %>
+ <%= product.name %>
+
+<% end %>
diff --git a/plugins/products/views/profile_editor/products_profile_info_contents.html.slim b/plugins/products/views/profile_editor/products_profile_info_contents.html.slim
new file mode 100644
index 0000000..890531e
--- /dev/null
+++ b/plugins/products/views/profile_editor/products_profile_info_contents.html.slim
@@ -0,0 +1,3 @@
+- if profile.enterprise?
+ h2= _('Products/Services catalog')
+ = labelled_form_field(_('Number of products/services displayed per page on catalog'), text_field(:profile_data, :products_per_catalog_page, size: 3))
diff --git a/plugins/products/views/search/products.html.erb b/plugins/products/views/search/products.html.erb
new file mode 120000
index 0000000..f2ff928
--- /dev/null
+++ b/plugins/products/views/search/products.html.erb
@@ -0,0 +1 @@
+../../../../app/views/search/search_page.html.erb
\ No newline at end of file
diff --git a/plugins/products/views/search/products.js.erb b/plugins/products/views/search/products.js.erb
new file mode 120000
index 0000000..880e571
--- /dev/null
+++ b/plugins/products/views/search/products.js.erb
@@ -0,0 +1 @@
+../../../../app/views/search/search.js.erb
\ No newline at end of file
diff --git a/plugins/recent_content/test/unit/recent_content_block_test.rb b/plugins/recent_content/test/unit/recent_content_block_test.rb
index 9ffb169..4cc56a1 100644
--- a/plugins/recent_content/test/unit/recent_content_block_test.rb
+++ b/plugins/recent_content/test/unit/recent_content_block_test.rb
@@ -1,7 +1,7 @@
require_relative '../test_helper'
class RecentContentBlockTest < ActiveSupport::TestCase
- INVALID_KIND_OF_ARTICLE = [EnterpriseHomepage, RssFeed, UploadedFile, Gallery, Folder, Blog, Forum]
+ INVALID_KIND_OF_ARTICLE = [RssFeed, UploadedFile, Gallery, Folder, Blog, Forum]
VALID_KIND_OF_ARTICLE = [RawHTMLArticle, TextArticle, TextileArticle, TinyMceArticle]
should 'describe itself' do
diff --git a/plugins/shopping_cart/features/step_definitions/products_steps.rb b/plugins/shopping_cart/features/step_definitions/products_steps.rb
new file mode 120000
index 0000000..f711ab6
--- /dev/null
+++ b/plugins/shopping_cart/features/step_definitions/products_steps.rb
@@ -0,0 +1 @@
+../../../products/features/step_definitions/products_steps.rb
\ No newline at end of file
diff --git a/plugins/shopping_cart/features/support/paths.rb b/plugins/shopping_cart/features/support/paths.rb
new file mode 100644
index 0000000..3dcb859
--- /dev/null
+++ b/plugins/shopping_cart/features/support/paths.rb
@@ -0,0 +1,2 @@
+require_relative '../../../../plugins/products/features/support/paths'
+
diff --git a/plugins/sniffer/lib/ext/product.rb b/plugins/sniffer/lib/ext/product.rb
deleted file mode 100644
index 4d4ded3..0000000
--- a/plugins/sniffer/lib/ext/product.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-require_dependency 'product'
-
-class Product
-
- include Noosfero::GeoRef
-
- # products x inputs
- # Fetches products the enterprise can be interested on buying based on the
- # inputs of said enterprise's products
- # Ex:
- # - Enterprise 1 has Product A that uses input X
- # - Enterprise 2 has Product B that belongs to category X
- # -> Enterprise 1 as a parameter to this scope would return product B
- scope :sniffer_plugin_suppliers_products, -> enterprise {
- select("DISTINCT products_2.*, 'product' as view")
- .joins('INNER JOIN inputs ON products.id = inputs.product_id')
- .joins('INNER JOIN categories ON inputs.product_category_id = categories.id')
- .joins('INNER JOIN products products_2 ON categories.id = products_2.product_category_id')
- .joins('INNER JOIN profiles ON profiles.id = products_2.profile_id')
- .where("products.profile_id = #{enterprise.id}")
- .where('profiles.public_profile = true AND profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id <> #{enterprise.id}")
- }
-
- # inputs x products
- # Fetches the enterprise's products that can be of interest to other
- # enterprises based on their products' inputs
- # Ex:
- # - Enterprise 1 has Product A that belongs to category X
- # - Enterprise 2 has Product B that uses input X
- # -> Enterprise 1 as a parameter to this scope would return product A
- # with an extra column `consumer_profile_id` equal to Enterprise 2 id
- scope :sniffer_plugin_consumers_products, -> enterprise {
- select("DISTINCT products_2.*, profiles.id as consumer_profile_id, 'product' as view")
- .joins('INNER JOIN inputs ON products.id = inputs.product_id')
- .joins('INNER JOIN categories ON inputs.product_category_id = categories.id')
- .joins('INNER JOIN products products_2 ON categories.id = products_2.product_category_id')
- .joins('INNER JOIN profiles ON profiles.id = products.profile_id')
- .where("products_2.profile_id = #{enterprise.id}")
- .where('profiles.public_profile = true AND profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id <> #{enterprise.id}")
- }
-
- # interest x products
- # Fetches products the enterprise can be interested on buying based on the
- # buyer interests definded by this enterprise's admin
- # Ex:
- # - Enterprise 1 has category X as a buyer interest
- # - Enterprise 2 has Product B that belongs to category X
- # -> Enterprise 1 as a parameter to this scope would return product B
- scope :sniffer_plugin_interests_suppliers_products, -> profile {
- from("profiles sniffer")
- .select("DISTINCT products.*, 'product' as view")
- .joins("INNER JOIN sniffer_plugin_opportunities AS op ON sniffer.id = op.profile_id AND op.opportunity_type = 'ProductCategory'")
- .joins('INNER JOIN categories ON op.opportunity_id = categories.id')
- .joins('INNER JOIN products ON products.product_category_id = categories.id')
- .joins('INNER JOIN profiles ON products.profile_id = profiles.id')
- .where("sniffer.id = #{profile.id} AND products.profile_id <> #{profile.id}")
- .where('profiles.public_profile = true AND profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id <> #{profile.id}")
- }
-
- # products x interests
- # Fetches products the enterprise can sell to others based on the buyer
- # interests definded by other enterprises' admins
- # Ex:
- # - Enterprise 1 has Product A that belongs to category X
- # - Enterprise 2 has category X as a buyer interest
- # -> Enterprise 1 as a parameter to this scope would return product A
- # with an extra column `consumer_profile_id` equal to Enterprise 2 id
- scope :sniffer_plugin_interests_consumers_products, -> profile {
- select("DISTINCT products.*, profiles.id as consumer_profile_id, 'product' as view")
- .joins('INNER JOIN categories ON categories.id = products.product_category_id')
- .joins("INNER JOIN sniffer_plugin_opportunities as op ON categories.id = op.opportunity_id AND op.opportunity_type = 'ProductCategory'")
- .joins('INNER JOIN profiles ON op.profile_id = profiles.id')
- .where("products.profile_id = #{profile.id}")
- .where('profiles.public_profile = true AND profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id <> #{profile.id}")
- }
-
- # knowledge x inputs
- scope :sniffer_plugin_knowledge_consumers_inputs, -> profile {
- select("DISTINCT products.*, articles.id AS knowledge_id, 'knowledge' as view")
- .joins('INNER JOIN inputs ON products.id = inputs.product_id')
- .joins("INNER JOIN article_resources ON article_resources.resource_id = inputs.product_category_id AND article_resources.resource_type = 'ProductCategory'")
- .joins('INNER JOIN articles ON article_resources.article_id = articles.id')
- .joins('INNER JOIN profiles ON products.profile_id = profiles.id')
- .where("articles.type = 'CmsLearningPlugin::Learning'")
- .where("articles.profile_id = #{profile.id}")
- .where("products.profile_id <> #{profile.id}")
- }
-
- # inputs x knowledge
- scope :sniffer_plugin_knowledge_suppliers_inputs, -> profile {
- select("DISTINCT products.*, profiles.id as supplier_profile_id, articles.id AS knowledge_id, 'knowledge' as view")
- .joins("INNER JOIN inputs ON products.id = inputs.product_id")
- .joins("INNER JOIN article_resources ON article_resources.resource_id = inputs.product_category_id AND article_resources.resource_type = 'ProductCategory'")
- .joins('INNER JOIN articles ON article_resources.article_id = articles.id')
- .joins('INNER JOIN profiles ON articles.profile_id = profiles.id')
- .where("articles.type = 'CmsLearningPlugin::Learning'")
- .where("articles.profile_id <> #{profile.id}")
- .where("products.profile_id = #{profile.id}")
- }
-
- # knowledge x interests
- scope :sniffer_plugin_knowledge_consumers_interests, -> profile {
- from('articles')
- .select("DISTINCT articles.id AS knowledge_id, op.opportunity_id AS product_category_id, profiles.id as profile_id, 'knowledge' as view")
- .joins('INNER JOIN article_resources ON articles.id = article_resources.article_id')
- .joins("INNER JOIN sniffer_plugin_opportunities as op ON article_resources.resource_id = op.opportunity_id AND op.opportunity_type = 'ProductCategory' AND article_resources.resource_type = 'ProductCategory'")
- .joins('INNER JOIN profiles ON op.profile_id = profiles.id')
- .where("articles.profile_id = #{profile.id}")
- .where('profiles.public_profile = true')
- .where('profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id <> #{profile.id}")
- }
-
- # interests x knowledge
- scope :sniffer_plugin_knowledge_suppliers_interests, -> profile {
- from('articles')
- .select("DISTINCT articles.id AS knowledge_id, op.opportunity_id AS product_category_id, profiles.id as profile_id, 'knowledge' as view")
- .joins('INNER JOIN article_resources ON articles.id = article_resources.article_id')
- .joins("INNER JOIN sniffer_plugin_opportunities as op ON article_resources.resource_id = op.opportunity_id AND op.opportunity_type = 'ProductCategory' AND article_resources.resource_type = 'ProductCategory'")
- .joins('INNER JOIN profiles ON articles.profile_id = profiles.id')
- .where("articles.profile_id <> #{profile.id}")
- .where('profiles.public_profile = true')
- .where('profiles.visible = true')
- .where('profiles.enabled = true')
- .where("profiles.id = #{profile.id}")
- }
-
- # searches for products as supplies for a given product category
- scope :sniffer_plugin_products_from_category, -> product_category {
- select("*, 'product' as view")
- .where(product_category_id: product_category.id)
- }
-
-end
diff --git a/plugins/sniffer/lib/ext/product_category.rb b/plugins/sniffer/lib/ext/product_category.rb
deleted file mode 100644
index 5d70bdd..0000000
--- a/plugins/sniffer/lib/ext/product_category.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_dependency 'product_category'
-
-class ProductCategory
-
- has_many :sniffer_plugin_enterprises, -> { distinct },
- through: :products, source: :enterprise
-
-end
diff --git a/plugins/sniffer/lib/ext/products_plugin/product.rb b/plugins/sniffer/lib/ext/products_plugin/product.rb
new file mode 100644
index 0000000..d826d9e
--- /dev/null
+++ b/plugins/sniffer/lib/ext/products_plugin/product.rb
@@ -0,0 +1,143 @@
+require_dependency 'products_plugin/product'
+
+class ProductsPlugin::Product
+
+ include Noosfero::GeoRef
+
+ # products x inputs
+ # Fetches products the enterprise can be interested on buying based on the
+ # inputs of said enterprise's products
+ # Ex:
+ # - Enterprise 1 has Product A that uses input X
+ # - Enterprise 2 has Product B that belongs to category X
+ # -> Enterprise 1 as a parameter to this scope would return product B
+ scope :sniffer_plugin_suppliers_products, -> enterprise {
+ select("DISTINCT products_2.*, 'product' as view")
+ .joins('INNER JOIN inputs ON products.id = inputs.product_id')
+ .joins('INNER JOIN categories ON inputs.product_category_id = categories.id')
+ .joins('INNER JOIN products products_2 ON categories.id = products_2.product_category_id')
+ .joins('INNER JOIN profiles ON profiles.id = products_2.profile_id')
+ .where("products.profile_id = #{enterprise.id}")
+ .where('profiles.public_profile = true AND profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id <> #{enterprise.id}")
+ }
+
+ # inputs x products
+ # Fetches the enterprise's products that can be of interest to other
+ # enterprises based on their products' inputs
+ # Ex:
+ # - Enterprise 1 has Product A that belongs to category X
+ # - Enterprise 2 has Product B that uses input X
+ # -> Enterprise 1 as a parameter to this scope would return product A
+ # with an extra column `consumer_profile_id` equal to Enterprise 2 id
+ scope :sniffer_plugin_consumers_products, -> enterprise {
+ select("DISTINCT products_2.*, profiles.id as consumer_profile_id, 'product' as view")
+ .joins('INNER JOIN inputs ON products.id = inputs.product_id')
+ .joins('INNER JOIN categories ON inputs.product_category_id = categories.id')
+ .joins('INNER JOIN products products_2 ON categories.id = products_2.product_category_id')
+ .joins('INNER JOIN profiles ON profiles.id = products.profile_id')
+ .where("products_2.profile_id = #{enterprise.id}")
+ .where('profiles.public_profile = true AND profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id <> #{enterprise.id}")
+ }
+
+ # interest x products
+ # Fetches products the enterprise can be interested on buying based on the
+ # buyer interests definded by this enterprise's admin
+ # Ex:
+ # - Enterprise 1 has category X as a buyer interest
+ # - Enterprise 2 has Product B that belongs to category X
+ # -> Enterprise 1 as a parameter to this scope would return product B
+ scope :sniffer_plugin_interests_suppliers_products, -> profile {
+ from("profiles sniffer")
+ .select("DISTINCT products.*, 'product' as view")
+ .joins("INNER JOIN sniffer_plugin_opportunities AS op ON sniffer.id = op.profile_id AND op.opportunity_type = 'ProductCategory'")
+ .joins('INNER JOIN categories ON op.opportunity_id = categories.id')
+ .joins('INNER JOIN products ON products.product_category_id = categories.id')
+ .joins('INNER JOIN profiles ON products.profile_id = profiles.id')
+ .where("sniffer.id = #{profile.id} AND products.profile_id <> #{profile.id}")
+ .where('profiles.public_profile = true AND profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id <> #{profile.id}")
+ }
+
+ # products x interests
+ # Fetches products the enterprise can sell to others based on the buyer
+ # interests definded by other enterprises' admins
+ # Ex:
+ # - Enterprise 1 has Product A that belongs to category X
+ # - Enterprise 2 has category X as a buyer interest
+ # -> Enterprise 1 as a parameter to this scope would return product A
+ # with an extra column `consumer_profile_id` equal to Enterprise 2 id
+ scope :sniffer_plugin_interests_consumers_products, -> profile {
+ select("DISTINCT products.*, profiles.id as consumer_profile_id, 'product' as view")
+ .joins('INNER JOIN categories ON categories.id = products.product_category_id')
+ .joins("INNER JOIN sniffer_plugin_opportunities as op ON categories.id = op.opportunity_id AND op.opportunity_type = 'ProductCategory'")
+ .joins('INNER JOIN profiles ON op.profile_id = profiles.id')
+ .where("products.profile_id = #{profile.id}")
+ .where('profiles.public_profile = true AND profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id <> #{profile.id}")
+ }
+
+ # knowledge x inputs
+ scope :sniffer_plugin_knowledge_consumers_inputs, -> profile {
+ select("DISTINCT products.*, articles.id AS knowledge_id, 'knowledge' as view")
+ .joins('INNER JOIN inputs ON products.id = inputs.product_id')
+ .joins("INNER JOIN article_resources ON article_resources.resource_id = inputs.product_category_id AND article_resources.resource_type = 'ProductCategory'")
+ .joins('INNER JOIN articles ON article_resources.article_id = articles.id')
+ .joins('INNER JOIN profiles ON products.profile_id = profiles.id')
+ .where("articles.type = 'CmsLearningPlugin::Learning'")
+ .where("articles.profile_id = #{profile.id}")
+ .where("products.profile_id <> #{profile.id}")
+ }
+
+ # inputs x knowledge
+ scope :sniffer_plugin_knowledge_suppliers_inputs, -> profile {
+ select("DISTINCT products.*, profiles.id as supplier_profile_id, articles.id AS knowledge_id, 'knowledge' as view")
+ .joins("INNER JOIN inputs ON products.id = inputs.product_id")
+ .joins("INNER JOIN article_resources ON article_resources.resource_id = inputs.product_category_id AND article_resources.resource_type = 'ProductCategory'")
+ .joins('INNER JOIN articles ON article_resources.article_id = articles.id')
+ .joins('INNER JOIN profiles ON articles.profile_id = profiles.id')
+ .where("articles.type = 'CmsLearningPlugin::Learning'")
+ .where("articles.profile_id <> #{profile.id}")
+ .where("products.profile_id = #{profile.id}")
+ }
+
+ # knowledge x interests
+ scope :sniffer_plugin_knowledge_consumers_interests, -> profile {
+ from('articles')
+ .select("DISTINCT articles.id AS knowledge_id, op.opportunity_id AS product_category_id, profiles.id as profile_id, 'knowledge' as view")
+ .joins('INNER JOIN article_resources ON articles.id = article_resources.article_id')
+ .joins("INNER JOIN sniffer_plugin_opportunities as op ON article_resources.resource_id = op.opportunity_id AND op.opportunity_type = 'ProductCategory' AND article_resources.resource_type = 'ProductCategory'")
+ .joins('INNER JOIN profiles ON op.profile_id = profiles.id')
+ .where("articles.profile_id = #{profile.id}")
+ .where('profiles.public_profile = true')
+ .where('profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id <> #{profile.id}")
+ }
+
+ # interests x knowledge
+ scope :sniffer_plugin_knowledge_suppliers_interests, -> profile {
+ from('articles')
+ .select("DISTINCT articles.id AS knowledge_id, op.opportunity_id AS product_category_id, profiles.id as profile_id, 'knowledge' as view")
+ .joins('INNER JOIN article_resources ON articles.id = article_resources.article_id')
+ .joins("INNER JOIN sniffer_plugin_opportunities as op ON article_resources.resource_id = op.opportunity_id AND op.opportunity_type = 'ProductCategory' AND article_resources.resource_type = 'ProductCategory'")
+ .joins('INNER JOIN profiles ON articles.profile_id = profiles.id')
+ .where("articles.profile_id <> #{profile.id}")
+ .where('profiles.public_profile = true')
+ .where('profiles.visible = true')
+ .where('profiles.enabled = true')
+ .where("profiles.id = #{profile.id}")
+ }
+
+ # searches for products as supplies for a given product category
+ scope :sniffer_plugin_products_from_category, -> product_category {
+ select("*, 'product' as view")
+ .where(product_category_id: product_category.id)
+ }
+
+end
diff --git a/plugins/sniffer/lib/ext/products_plugin/product_category.rb b/plugins/sniffer/lib/ext/products_plugin/product_category.rb
new file mode 100644
index 0000000..3371082
--- /dev/null
+++ b/plugins/sniffer/lib/ext/products_plugin/product_category.rb
@@ -0,0 +1,9 @@
+require_dependency 'products_plugin/product_category'
+
+module ProductsPlugin
+ class ProductCategory
+
+ has_many :sniffer_plugin_enterprises, -> { distinct }, through: :products, source: :profile
+
+ end
+end
diff --git a/plugins/sniffer/lib/ext/profile.rb b/plugins/sniffer/lib/ext/profile.rb
index c73efec..b9f9e8e 100644
--- a/plugins/sniffer/lib/ext/profile.rb
+++ b/plugins/sniffer/lib/ext/profile.rb
@@ -7,7 +7,7 @@ class Profile
has_many :sniffer_opportunities, class_name: 'SnifferPlugin::Opportunity', dependent: :destroy
has_many :sniffer_interested_product_categories, -> {
where 'sniffer_plugin_opportunities.opportunity_type = ?', 'ProductCategory'
- }, through: :sniffer_opportunities, source: :product_category, class_name: 'ProductCategory'
+ }, through: :sniffer_opportunities, source: :product_category
attr_accessor :sniffer_interested_product_category_string_ids
descendants.each do |k|
@@ -22,7 +22,7 @@ class Profile
self.sniffer_interested_product_categories = []
r = environment.product_categories.find ids
self.sniffer_interested_product_categories = ids.collect{ |id| r.detect {|x| x.id == id.to_i} }
- self.sniffer_opportunities.where(:opportunity_id => ids).each{|o| o.opportunity_type = 'ProductCategory'; o.save! }
+ self.sniffer_opportunities.where(opportunity_id: ids).each{|o| o.opportunity_type = 'ProductCategory'; o.save! }
end
def sniffer_categories
diff --git a/plugins/sniffer/models/sniffer_plugin/opportunity.rb b/plugins/sniffer/models/sniffer_plugin/opportunity.rb
index c93f9ee..36b76e9 100644
--- a/plugins/sniffer/models/sniffer_plugin/opportunity.rb
+++ b/plugins/sniffer/models/sniffer_plugin/opportunity.rb
@@ -9,8 +9,7 @@ class SnifferPlugin::Opportunity < ApplicationRecord
# for has_many :through
belongs_to :product_category, -> {
where 'sniffer_plugin_opportunities.opportunity_type = ?', 'ProductCategory'
- }, class_name: 'ProductCategory', foreign_key: :opportunity_id
-
+ }, class_name: '::ProductsPlugin::ProductCategory', foreign_key: :opportunity_id
# getter
def product_category
opportunity_type == 'ProductCategory' ? opportunity : nil
diff --git a/plugins/sniffer/test/integration/sniffer_map_test.rb b/plugins/sniffer/test/integration/sniffer_map_test.rb
index 4585cfc..a994f4c 100644
--- a/plugins/sniffer/test/integration/sniffer_map_test.rb
+++ b/plugins/sniffer/test/integration/sniffer_map_test.rb
@@ -1,4 +1,4 @@
-require 'test_helper'
+require_relative '../test_helper'
class SnifferMapTest < ActionDispatch::IntegrationTest
@@ -22,7 +22,7 @@ class SnifferMapTest < ActionDispatch::IntegrationTest
end
# Create 2 products to each enterprise with its own category:
8.times do |i| n = (i+=1).to_s
- @c[i] = fast_create(ProductCategory, :name => 'Category'+n)
+ @c[i] = create(ProductCategory, :name => 'Category'+n)
@p[i] = fast_create(Product,
:product_category_id => @c[i].id, :profile_id => @e[(i+1)/2].id
)
diff --git a/plugins/sniffer/test/test_helper.rb b/plugins/sniffer/test/test_helper.rb
new file mode 100644
index 0000000..ce1c602
--- /dev/null
+++ b/plugins/sniffer/test/test_helper.rb
@@ -0,0 +1,2 @@
+require_relative '../../products/test/test_helper'
+
diff --git a/plugins/sniffer/test/unit/ext/product_category_test.rb b/plugins/sniffer/test/unit/ext/product_category_test.rb
index 856251a..787c00d 100644
--- a/plugins/sniffer/test/unit/ext/product_category_test.rb
+++ b/plugins/sniffer/test/unit/ext/product_category_test.rb
@@ -1,9 +1,9 @@
-require 'test_helper'
+require_relative '../../test_helper'
class ProductCategoryTest < ActiveSupport::TestCase
def setup
- @category = fast_create(ProductCategory, :name => 'Category 1')
+ @category = create ProductCategory, :name => 'Category 1'
end
should 'provide all enterprises that have products with a product category' do
@@ -11,7 +11,7 @@ class ProductCategoryTest < ActiveSupport::TestCase
e2 = fast_create(Enterprise, :identifier => 'ent2' )
e3 = fast_create(Enterprise, :identifier => 'ent3' )
- c2 = fast_create(ProductCategory, :name => 'Category 2')
+ c2 = create(ProductCategory, :name => 'Category 2')
# Enteprise 1 and Enteprise 2 have one category 1 products
fast_create(Product, :product_category_id => @category.id, :profile_id => e1.id )
diff --git a/plugins/sniffer/test/unit/ext/profile_test.rb b/plugins/sniffer/test/unit/ext/profile_test.rb
index 36889f9..0ac7860 100644
--- a/plugins/sniffer/test/unit/ext/profile_test.rb
+++ b/plugins/sniffer/test/unit/ext/profile_test.rb
@@ -1,4 +1,4 @@
-require 'test_helper'
+require_relative '../../test_helper'
class ProfileTest < ActiveSupport::TestCase
@@ -27,10 +27,10 @@ class ProfileTest < ActiveSupport::TestCase
e2 = fast_create(Enterprise, :identifier => 'ent2' )
e3 = fast_create(Enterprise, :identifier => 'ent3' )
# Categories:
- c1 = fast_create(ProductCategory, :name => 'Category 1')
- c2 = fast_create(ProductCategory, :name => 'Category 2')
- c3 = fast_create(ProductCategory, :name => 'Category 3')
- c4 = fast_create(ProductCategory, :name => 'Category 4') # not used by products
+ c1 = create(ProductCategory, :name => 'Category 1')
+ c2 = create(ProductCategory, :name => 'Category 2')
+ c3 = create(ProductCategory, :name => 'Category 3')
+ c4 = create(ProductCategory, :name => 'Category 4') # not used by products
# Products (for enterprise 1):
p1 = fast_create(Product, :product_category_id => c1.id, :profile_id => e1.id )
p2 = fast_create(Product, :product_category_id => c2.id, :profile_id => e1.id )
@@ -71,8 +71,8 @@ class ProfileTest < ActiveSupport::TestCase
e1 = fast_create(Enterprise, :identifier => 'ent1' )
e2 = fast_create(Enterprise, :identifier => 'ent2' )
# Categories:
- c1 = fast_create(ProductCategory, :name => 'Category 1')
- c2 = fast_create(ProductCategory, :name => 'Category 2')
+ c1 = create(ProductCategory, :name => 'Category 1')
+ c2 = create(ProductCategory, :name => 'Category 2')
# Products (for enterprise 1):
p1 = fast_create(Product, :product_category_id => c1.id, :profile_id => e1.id )
diff --git a/plugins/statistics/install.rb b/plugins/statistics/install.rb
deleted file mode 100644
index 84357d1..0000000
--- a/plugins/statistics/install.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-if ENV['CI']
- system 'script/noosfero-plugins -q enable products'
- exit $?.exitstatus
-end
-
diff --git a/plugins/statistics/test/test_helper.rb b/plugins/statistics/test/test_helper.rb
index 1d8d247..8c38fd0 100644
--- a/plugins/statistics/test/test_helper.rb
+++ b/plugins/statistics/test/test_helper.rb
@@ -1 +1,6 @@
+# can't be done in install.rb as this is a baseplugin
+if ENV['CI']
+ system 'script/noosfero-plugins -q enable products'
+end
+
require 'test_helper'
diff --git a/plugins/suppliers/lib/ext/orders_plugin/item.rb b/plugins/suppliers/lib/ext/orders_plugin/item.rb
index d27dc33..aafa1b4 100644
--- a/plugins/suppliers/lib/ext/orders_plugin/item.rb
+++ b/plugins/suppliers/lib/ext/orders_plugin/item.rb
@@ -1,7 +1,9 @@
-require_dependency "orders_plugin/item"
+if defined? OrdersPlugin
+ require_dependency "orders_plugin/item"
-class OrdersPlugin::Item
+ class OrdersPlugin::Item
- delegate :supplier, to: :product
+ delegate :supplier, to: :product
+ end
end
diff --git a/plugins/suppliers/lib/ext/profile.rb b/plugins/suppliers/lib/ext/profile.rb
index 8d20d37..5512a47 100644
--- a/plugins/suppliers/lib/ext/profile.rb
+++ b/plugins/suppliers/lib/ext/profile.rb
@@ -1,14 +1,6 @@
require_dependency 'profile'
require_dependency 'community'
-# FIXME: should be on the core
-([Profile] + Profile.descendants).each do |subclass|
-subclass.class_eval do
-
- has_many :products, foreign_key: :profile_id
-
-end
-end
class Profile
def create_product?
true
diff --git a/public/images/catalog-expanders.png b/public/images/catalog-expanders.png
deleted file mode 100644
index 395e0b2..0000000
Binary files a/public/images/catalog-expanders.png and /dev/null differ
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index a23bd43..fff7e9b 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -27,8 +27,6 @@
* views speficics
*= require add-and-join.js
*= require report-abuse.js
-*= require manage-products.js
-*= require catalog.js
*= require autogrow.js
*= require require_login.js
*= require slick.js
@@ -240,8 +238,6 @@ function redirect_to(url) {
document.location=url;
}
-/* Products edition */
-
function numbersonly(e, separator) {
var key;
var keychar;
diff --git a/public/javascripts/catalog.js b/public/javascripts/catalog.js
deleted file mode 100644
index 79e56e2..0000000
--- a/public/javascripts/catalog.js
+++ /dev/null
@@ -1,29 +0,0 @@
-(function($) {
-
- function toggle_expandbox(element, open) {
- element.clicked = open;
- $(element).toggleClass('open', open);
- }
-
- $('#product-list .expand-box').live('click', function () {
- var me = this;
- $('.expand-box').each(function(index, element){
- if ( element != me ) toggle_expandbox(element, false);
- });
- toggle_expandbox(me, !me.clicked);
- return false;
- });
-
- $('#product-list .float-box').live('click', function () {
- return false;
- });
-
- $(document).click(function (event) {
- if ($(event.target).parents('.expand-box').length == 0) {
- $('#product-list .expand-box').each(function(index, element){
- toggle_expandbox(element, false);
- });
- }
- });
-
-})(jQuery);
diff --git a/public/javascripts/manage-products.js b/public/javascripts/manage-products.js
deleted file mode 100644
index 919af6b..0000000
--- a/public/javascripts/manage-products.js
+++ /dev/null
@@ -1,194 +0,0 @@
-(function($) {
-
- $("#manage-product-details-button").live('click', function() {
- $("#product-price-details").find('.loading-area').addClass('small-loading');
- url = $(this).attr('href');
- $.get(url, function(data){
- $("#manage-product-details-button").hide();
- $("#display-price-details").hide();
- $("#display-manage-price-details").html(data);
- $("#product-price-details").find('.loading-area').removeClass('small-loading');
- });
- return false;
- });
-
- $(".cancel-price-details").live('click', function() {
- if ( !$(this).hasClass('form-changed') ) {
- cancelPriceDetailsEdition();
- } else {
- if (confirm($(this).attr('data-confirm'))) {
- cancelPriceDetailsEdition();
- }
- }
- return false;
- });
-
- $('#manage-product-details-form').live('submit', function(data) {
- var form = this;
- $(form).find('.loading-area').addClass('small-loading');
- $(form).css('cursor', 'progress');
- var request = $.ajax(form.action, {
- type: 'POST',
- dataType: 'html',
- data: $(form).serialize()
- });
- request.done(function(data, textStatus, jqXHR) {
- $('#display-manage-price-details').html(data);
- $('#manage-product-details-button').show();
- });
- request.fail(function(jqXHR, textStatus, errorThrown) {
- log.error('manage_product_details', 'Request failed', errorThrown);
- alert('manage_product_details\nRequest failed: '+ errorThrown +
- '\n\nPlease, contact the site administrator.');
- $('#display-manage-price-details .loading-area').hide();
- });
- if ($('#progressbar-icon').hasClass('ui-icon-check')) {
- display_notice($('#progressbar-icon').attr('data-price-described-notice'));
- }
- return false;
- });
-
- $("#add-new-cost").live('click', function() {
- $('#display-product-price-details tbody').append($('#new-cost-fields tbody').html());
- return false;
- });
-
- $(".cancel-new-cost").live('click', function() {
- $(this).parents('tr').remove();
- calculateValuesForBar();
- return false;
- });
-
- $("#product-info-form").live('submit', function(data) {
- var form = this;
- updatePriceCompositionBar(form);
- });
-
- $("form.edit_input").live('submit', function(data) {
- var form = this;
- inputs_cost_update_url = $(form).find('#inputs-cost-update-url').val();
- $.get(inputs_cost_update_url, function(data){
- $(".inputs-cost span").html(data);
- });
- updatePriceCompositionBar(form);
- return false;
- });
-
- $("#manage-product-details-form .price-details-price").live('blur', function(data) { calculateValuesForBar(); });
-
- function cancelPriceDetailsEdition() {
- $("#manage-product-details-button").show();
- $("#display-price-details").show();
- $("#display-manage-price-details").html('');
- };
-
-})(jQuery);
-
-function updatePriceCompositionBar(form) {
- bar_url = jQuery(form).find('.bar-update-url').val();
- jQuery.ajax({
- url : bar_url,
- success : function(data) {
- jQuery("#price-composition-bar").html(data);
- },
- complete : function() {
- jQuery('form #product_price').val(currencyToFloat(jQuery('#progressbar-text .product_price').html(), currency_format.separator, currency_format.delimiter));
- jQuery('form #product_inputs_cost').val(currencyToFloat(jQuery('#display-product-price-details .inputs-cost span').html(), currency_format.separator, currency_format.delimiter, currency_format.unit));
- calculateValuesForBar();
- }
- });
-};
-
-function enablePriceDetailSubmit() {
- jQuery('#manage-product-details-form input.submit').removeAttr("disabled").removeClass('disabled');
-}
-
-function calculateValuesForBar() {
- jQuery('.cancel-price-details').addClass('form-changed');
- var product_price = parseFloat(jQuery('form #product_price').val());
- var total_cost = parseFloat(jQuery('form #product_inputs_cost').val());
-
- jQuery('form .price-details-price').each(function() {
- var this_val = parseFloat(jQuery(this).val().replace(currency_format.separator, '.')) || 0;
- total_cost = total_cost + this_val;
- });
- enablePriceDetailSubmit();
-
- var described = (product_price - total_cost) == 0;
- var percentage = total_cost * 100 / product_price;
- priceCompositionBar(percentage, described, total_cost, product_price);
-}
-
-function addCommas(nStr) {
- nStr += '';
- var x = nStr.split('.');
- var x1 = x[0];
- var x2 = x.length > 1 ? '.' + x[1] : '';
- var rgx = /(\d+)(\d{3})/;
- while (rgx.test(x1)) {
- x1 = x1.replace(rgx, '$1' + ',' + '$2');
- }
- return x1 + x2;
-}
-
-function floatToCurrency(value, sep, del, cur) {
- var ret = '';
- if (cur) ret = cur + ' ';
- if (!sep) sep = '.';
- if (!del) del = ',';
- return ret + addCommas(parseFloat(value).toFixed(2).toString()).replace('.', '%sep%').replace(',', del).replace('%sep%', sep);
-}
-
-function currencyToFloat(value, sep, del, cur) {
- var val = value;
- if (cur) val = val.replace(cur + ' ', '');
- if (!sep) sep = '.';
- if (!del) del = ',';
- return parseFloat(val.replace(del, '').replace(sep, '.'));
-}
-
-function productionCostTypeChange(select, url, question, error_msg) {
- if (select.value == '') {
- var newType = prompt(question);
- if (newType) {
- jQuery.ajax({
- url: url + "/" + newType,
- dataType: 'json',
- success: function(data, status, ajax){
- if (data.ok) {
- var opt = jQuery('' + newType + ' ');
- opt.insertBefore(jQuery("option:last", select));
- select.selectedIndex = select.options.length - 2;
- opt.clone().insertBefore('#new-cost-fields .production-cost-selection option:last');
- } else {
- alert(data.error_msg);
- }
- },
- error: function(ajax, status, error){
- alert(error_msg);
- }
- });
- }
- }
-}
-
-function priceCompositionBar(value, described, total_cost, price) {
- jQuery(function($) {
- var bar_area = $('#price-composition-bar');
- $(bar_area).find('#progressbar').progressbar({
- value: value
- });
- $(bar_area).find('.production_cost').html(floatToCurrency(total_cost, currency_format.separator, currency_format.delimiter));
- $(bar_area).find('.product_price').html(floatToCurrency(price, currency_format.separator, currency_format.delimiter));
- if (described) {
- $(bar_area).find('#progressbar-icon').addClass('ui-icon-check');
- $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-described-message'));
- $(bar_area).find('div.ui-progressbar-value').addClass('price-described');
- } else {
- $(bar_area).find('#progressbar-icon').removeClass('ui-icon-check');
- $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-not-described-message'));
- $(bar_area).find('div.ui-progressbar-value').removeClass('price-described');
-
- }
- });
-}
diff --git a/public/javascripts/product_categories.js b/public/javascripts/product_categories.js
deleted file mode 100644
index 409b753..0000000
--- a/public/javascripts/product_categories.js
+++ /dev/null
@@ -1,40 +0,0 @@
-product_categories = {
-
- autocomplete: {
- search_url: '',
- select_url: '',
-
- load: function(elem) {
- elem = jQuery(elem)
-
- elem.autocomplete({
- minLength: 3,
- selectFirst: true,
-
- //define callback to retrieve results
- source: function(req, add) {
- //pass request to server
- //The alt attribute contains the wordpress callback action
- var params = { term: req.term };
- jQuery.getJSON(product_categories.autocomplete.search_url, params, function(data) {
- add(data);
- });
- },
-
- focus: function( event, ui ) {
- jQuery(this).val(ui.item.label);
- return false;
- },
-
- select: function(e, ui) {
- jQuery('#categories-container').load(product_categories.autocomplete.select_url, {category_id: ui.item.value})
-
- jQuery(this).val("")
- },
-
- });
-
- },
- },
-
-};
diff --git a/public/stylesheets/application.scss b/public/stylesheets/application.scss
index 46dd15c..770613f 100644
--- a/public/stylesheets/application.scss
+++ b/public/stylesheets/application.scss
@@ -65,12 +65,8 @@
@import 'menu-submenu';
@import 'category';
-@import 'product-category';
@import 'enterprises';
-@import 'catalog';
-@import 'product';
-@import 'product-category';
@import 'site-map';
@import 'portal-news';
diff --git a/public/stylesheets/blocks.scss b/public/stylesheets/blocks.scss
index c92db6b..2a136e6 100644
--- a/public/stylesheets/blocks.scss
+++ b/public/stylesheets/blocks.scss
@@ -24,8 +24,6 @@
@import 'blocks/disabled-enterprise-message';
@import 'blocks/sellers-search';
-@import 'blocks/products';
-@import 'blocks/featured-products';
.msie7 .block .menu-submenu {
z-index: 4;
diff --git a/public/stylesheets/blocks/featured-products.scss b/public/stylesheets/blocks/featured-products.scss
deleted file mode 100644
index 7d3e2b8..0000000
--- a/public/stylesheets/blocks/featured-products.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-
-.featured-product-items {
- width: 100%;
- display: table;
- margin: 0 auto;
- text-align: center;
-}
-.featured-product-items ul {
- display: table-row;
-}
-.featured-product-item {
- list-style-type: none;
- display: table-cell !important;
-}
-.featured-product-item div {
- margin: 0 auto;
-}
-.featured-products-list {
- padding: 0;
-}
-.featured-product-arrow {
- float: left;
- width: 20px;
- background-repeat: no-repeat;
- height: 160px;
- background-position: center 55px;
-}
-.featured-product-arrow span {
- display: none;
-}
-.featured-product-prev {
- background-image: url(../designs/icons/tango/Tango/16x16/actions/go-previous.png);
-}
-.featured-product-next {
- background-image: url(../designs/icons/tango/Tango/16x16/actions/go-next.png);
-}
-.featured-products-block-container {
- width: 92%;
-}
-.box-2 .featured-products-block-container, .box-3 .featured-products-block-container {
- width: 78%;
-}
-.featured-products-group {
- width: 100%;
- margin: 0 auto;
- text-align: center;
-}
-.featured-product-desc {
- display: none;
-}
-.featured-products-block-container, .featured-products-group {
- overflow: hidden;
- float: left;
- height: 160px;
- position: relative;
-}
-.featured-products-group ul {
- padding: 0;
- padding-left: 4px;
-}
-.featured-products-footer {
- clear: both;
-}
-.featured-product-info {
- position: absolute;
- top: 0;
- z-index: 9999;
- height: 125px;
- overflow: hidden;
- font-size: 11px;
- background-color: #fff;
- opacity: 0.7;
- border: 1px solid #333;
- padding: 5px;
- text-align: left;
-}
-.box-2 .featured-product-info, .box-3 .featured-product-info {
- width: 110px;
- margin-left: 50%;
- left: -60px;
-}
-#content .featured-product-info h3 {
- font-size: 11px;
-}
diff --git a/public/stylesheets/blocks/products.scss b/public/stylesheets/blocks/products.scss
deleted file mode 100644
index 7640c05..0000000
--- a/public/stylesheets/blocks/products.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-
-.products-block ul {
- margin: 0px;
- padding: 0px 5px 0px 0px;
- display: table;
- border-spacing: 5px;
-}
-#content .products-block li {
- margin: 0px;
- padding: 0px;
- list-style: none;
- list-style-image: none;
- font-size: 12px;
- height: 64px;
- display: table-row;
-}
-#content .products-block li a {
- background-repeat: no-repeat;
- background-position: 5px 50%;
- display: table-cell;
- vertical-align: middle;
- padding: 5px 2px 5px 60px;
- height: 50px;
- overflow: hidden;
- text-decoration: none;
-}
-.msie #content .products-block li a {
- display: block;
-}
-#content .products-block li a:hover {
- color: #fff;
-}
diff --git a/public/stylesheets/catalog.scss b/public/stylesheets/catalog.scss
deleted file mode 100644
index 907e479..0000000
--- a/public/stylesheets/catalog.scss
+++ /dev/null
@@ -1,247 +0,0 @@
-
-#product-catalog {
- text-align: center;
-}
-
-.product-catalog-ctrl {
- float: right;
-}
-
-#product-list {
- display: inline-block;
- text-align: left;
- line-height: 20px;
- margin: 0px;
- padding: 0px;
- list-style: none;
-}
-#product-list ul {
- margin: 0px;
- padding: 0px;
- list-style: none;
-}
-#product-list li.product {
- display: inline-block;
- width: 200px;
- min-height: 280px;
- padding: 10px 15px;
- margin-bottom: 10px;
- vertical-align: top;
-}
-#product-list .expand-box:hover {
- background-color: #28F091;
-}
-#product-list .expand-box {
- background-color: #1EB46D;
- margin-bottom: 3px;
- -moz-border-radius: 10px 0px 0px 10px;
- -webkit-border-radius: 10px 0px 0px 10px;
- border-radius: 10px 0px 0px 10px;
- position: relative;
-}
-#product-list .expand-box > span {
- padding-left: 20px;
- font-size: 0.70em;
- color: white;
- font-weight: bold;
- background: url(../images/catalog-expanders.png) no-repeat;
- display: block;
- line-height: 15px;
- background-position: left 100%;
- cursor: pointer;
-}
-#product-list .expand-box.open > span {
- background-position: left top;
-}
-#product-list .expand-box-corner {
-}
-#product-list li.product .product-qualifiers {
- font-size: 9px;
- line-height: normal;
-}
-#product-list li.product .product-qualifiers > span {
- font-weight: bold;
- display: block;
- margin-top: 8px;
-}
-#product-list li.product .product-qualifiers > span,
-#product-list li.product .expand-box > span {
- text-transform: uppercase;
-}
-#product-list li.product .expand-box .float-box {
- display: none;
- position: absolute;
- left: -220px;
- top: -11px;
- z-index: 10;
-}
-#product-list li.product .expand-box.open .float-box {
- display: block;
-}
-#product-list li.product .expand-box .content {
- font-size: 11px;
- padding: 6px 5px;
- overflow: auto;
- max-height: 200px;
- width: 200px;
- border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- background: #DCFFD7;
- border: 2px solid #1EB46D;
- min-height: 30px;
- float: left;
- text-align: left;
-}
-#product-list li.product .expand-box .arrow {
- border-left: 6px solid #1EB46D;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- margin-top: 13px;
- float: right;
-}
-
-#product-list li.product.not-available .expand-box {
- background-color: #DCF3E9;
-}
-#product-list li.product.not-available .product-link a,
-#product-list li.product.not-available .product-qualifiers,
-#product-list li.product.not-available .product-price-line,
-#product-list li.product.not-available .product-price,
-#product-list li.product.not-available .product-unit {
- color: #ACACAC !important;
-}
-#product-list .product-link {
- margin-top: 5px;
- margin-bottom: 5px;
- color: #006672;
- font-weight: bold;
- text-align: left;
-}
-#product-list .prop {
- float:right;
- width:1px;
-}
-#product-list .min50px {
- height:50px;
-}
-#product-list .product-row-clear {
- clear:both;
- height:1px;
- overflow:hidden;
-}
-
-#product-list .product-price-line {
- margin: 0 0 8px;
- display: block;
- clear: both;
-}
-#product-list .product-price {
- font-weight: bold;
-}
-#product-list .product-price,
-#product-list .product-unit {
- color: #0194C7;
-}
-#product-list .product-unit,
-#product-list .product-discount,
-#product-list .product-discount-by {
- font-size: 9px;
- margin-right: 3px;
-}
-#product-list .product-discount,
-#product-list .product-price {
- float: left;
- line-height: 15px;
- margin-right: 3px;
-}
-#product-list .product-discount span {
- text-decoration: line-through;
-}
-#product-list .product-discount-by {
- text-decoration: none !important;
-}
-
-#product-list .search-product-input-dots-to-price {
- width: 100%;
- margin: 0;
-}
-#product-list .search-product-input-name {
- background-color: #DCFFD7;
- max-width: 101px;
-}
-#product-list .search-product-input-price {
- background-color: #DCFFD7;
-}
-
-#product-list .catalog-item-extras {
- position: absolute;
- bottom: 0px;
- right: 0px;
-}
-#product-list .product-big {
- background-repeat: no-repeat;
- background-position: 50% 50%;
- display: block;
- height: 160px;
-}
-#product-list .ui-button {
- margin: 0;
-}
-#product-list .ui-button-text {
- color: #D38D5F;
- font-size: 0.8em;
- padding: 0.1em 0.3em 0.1em 3em;
-}
-#product-list .product-big span {
- display: none;
-}
-#product-list .product-image-link {
- position: relative;
- height: 160px;
- border: 1px solid #BFBFBF;
- position: relative; /* work arround msie bug */
- text-align: center;
- vertical-align: middle;
-}
-#product-list .product-image-link .no-image {
- line-height: 145px;
- text-align: center;
- color: #777;
- font-size: 9px;
- font-weight: bold;
- text-transform: uppercase;
- letter-spacing: 1px;
- user-select: none;
- -moz-user-select: none;
- -khtml-user-select: none;
- -webkit-user-select: none;
-}
-#product-list li.product-unavailable {
- text-transform: uppercase;
- color: #FF6261;
- font-weight: bold;
- line-height: 40px;
-}
-#product-list h3 {
- margin: 0px;
- padding: 0px;
- font-size: 120%;
-}
-.msie #product-list h3 {
- margin-top: -15px;
-}
-
-#product-list .highlighted img.star {
- position: absolute;
- top: 2px;
- right: 2px;
- z-index: 1;
-}
-
-#breadcrumb {
- font-size: 16px;
- margin: 15px 0;
- text-align: left;
-}
-
diff --git a/public/stylesheets/product-category.scss b/public/stylesheets/product-category.scss
deleted file mode 100644
index 3c9c052..0000000
--- a/public/stylesheets/product-category.scss
+++ /dev/null
@@ -1,90 +0,0 @@
-
-/* * * icons for product category on profile * * */
-
-#content .product-category-icons {
- position: absolute;
- top: 1px;
- right: 1px;
-}
-#content .profile-list-block .product-category-icons, #content .search-results-innerbox .product-category-icons {
- top: 3px;
- right: 3px;
-}
-#content .product-category-icons .header, #content .product-cat-icon span {
- display: none;
-}
-#content .product-cat-icon {
- display: block;
- width: 13px;
- height: 13px;
- margin-bottom: 1px;
-}
-/* * * category ajax selector * * */
-#category-ajax-selector .category-helper-label {
- font-size: 16px;
- color: rgb(158, 158, 158);
- padding: 5px 0px;
-}
-#category-ajax-selector {
- border: 1px solid #AAA;
- padding: 3px 10px 10px 10px;
- margin: 0px 0px 0px 0px;
- position: relative;
- font-size: 10px;
- background-color: #fcfcf9;
-}
-#category-ajax-selector a {
- font-size: 12px;
-}
-#selected-categories {
- padding-bottom: 5px;
-}
-#selected-categories .label {
- font-size: 16px;
- margin-bottom: 10px;
- margin-top: 5px;
-}
-.selected-category {
- padding: 2px 0;
-}
-#category-ajax-selector .box-title {
- position: absolute;
- top: -30px;
- left: 30px;
- line-height: 19px;
- padding: 0px 10px;
- border: 1px solid #AAA;
- border-bottom: none;
- background: #EEE;
- float: left;
-}
-.msie6 #category-ajax-selector .box-title {
- top: -29px;
-}
-#category-ajax-selector .select-subcategory-link,
-.select-subcategory-link {
- border: 1px solid #BBB;
- padding: 1px 3px;
- margin: 0px 1px;
- text-decoration: none;
- white-space: nowrap;
- font-size: 12px;
- line-height: 20px;
- border-radius: 3px;
-}
-#category-ajax-selector .selected-category .select-subcategory-link {
- border: 0;
-}
-#category-ajax-selector .select-subcategory-link:hover,
-.select-subcategory-link:hover {
- background-color: black;
-}
-#category-ajax-selector .button {
- top: 4px;
- right: 2px;
-}
-#category-ajax-selector hr {
- border: 0;
- border-bottom: 1px solid #EEE;
- margin-top: 15px;
-}
diff --git a/public/stylesheets/product.scss b/public/stylesheets/product.scss
deleted file mode 100644
index 736fa7f..0000000
--- a/public/stylesheets/product.scss
+++ /dev/null
@@ -1,231 +0,0 @@
-@import 'product/inputs';
-@import 'product/categories-selection';
-
-.link-to-remote {
- position: relative;
-}
-.product-search-filter {
-}
-
-.controller-catalog #show_product .product-pic {
- border: 1px solid #D3D7CF;
-}
-#show_product, #category-product-edition {
- background-color: transparent;
- position: relative;
- padding: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-#show_product h2, #category-product-edition h2 {
- margin-top: 0px;
-}
-#product-category, .product-category-hierarchy {
- margin-top: 40px;
- margin-bottom: 12px;
- padding-left: 7px;
-}
-#product-category {
- height: 18px;
-}
-#product-category p {
- display: inline;
-}
-#category-product-edition {
- padding-left: 10px;
- padding-right: 10px;
-}
-#display-product-name, #display-product-category {
- float: left;
-}
-#product-details {
- padding-top: 10px;
- padding-bottom: 10px;
- position: relative;
-}
-#edit-product-name {
- margin-top: 10px;
-}
-#product-name, #product-details {
- position: relative;
- clear: left;
-}
-#product-details, #product-info, .input-item {
- overflow: hidden;
-}
-#product-info {
- width: 335px;
- text-align: left;
- min-height: 150px;
- padding-bottom: 5px;
-}
-#display-product-info .field-value {
- font-weight: bold;
-}
-#edit-product-category {
- padding: 15px 5px 10px;
-}
-#product-info .field-name {
- margin-top: 5px;
- margin-bottom: 15px;
-}
-.edit_product #product_price, .edit_product #product_discount {
- width: 110px;
-}
-#product_unit {
- width: 100px;
-}
-#product-info .section-title {
- display: none;
-}
-#product-qualifiers {
- padding-left: 0px;
-}
-#product-qualifiers li {
- list-style: none;
-}
-#product-image {
- text-align: center;
- padding: 10px;
- width: 250px;
- margin-right: 10px;
- margin-bottom: 5px;
- float: left;
- border: 1px solid #AAA;
-}
-#product-image p {
- font-size: 11px;
- font-style: italic;
- margin-top: 0px;
- color: #555;
-}
-#display-product-image {
- margin-bottom: 10px;
- overflow: hidden;
-}
-#edit-product-image {
- position: relative;
- margin-top: 5px;
-}
-#product-qualifiers-list {
- padding: 0px;
- margin-bottom: 10px;
-}
-#product-qualifiers-list li {
- list-style: none;
-}
-#product-qualifiers-list .product-qualifier-title, #product-qualifiers-list .product-certifier-title {
- margin-right: 20px;
-}
-#edit-product-button-ui-inputs {
- margin-top: 20px;
-}
-#new-product-input h3 {
- margin-top: 0px;
-}
-.input-image .ui-icon, #display-add-input-button .hint {
- display: none;
-}
-#product-qualifiers-list .icon-delete {
- margin-left: 10px;
-}
-#product-qualifiers-list .icon-add {
- margin-top: 5px;
-}
-#display-product-info .unavailable-product .product-price {
- text-decoration: line-through;
- color: #555;
-}
-#display-product-info .alert {
- font-weight: bold;
- color: #D33;
- margin-top: 10px;
-}
-.selected-unit {
- font-weight: bold;
-}
-
-/* * * * * * Price details * * * * * */
-
-#display-price-details .price-details-list {
- padding-left: 0px;
-}
-
-#display-price-details .price-details-list li {
- list-style: none;
-}
-
-#display-price-details .price-details-list li .price-detail-name {
- width: 200px;
-}
-
-#display-price-details .price-details-list li .price-detail-name,
-#display-price-details .price-details-list li .price-detail-price {
- display: inline-block;
-}
-
-#manage-product-details-form .formfieldline {
- white-space: nowrap;
-}
-
-#manage-product-details-form .formlabel,
-#manage-product-details-form .formfield {
- display: inline-block;
-}
-
-#manage-product-details-form #add-new-cost {
- float: right;
-}
-
-/* * * Progress bar on price details edition * * */
-
-#display-manage-price-details .ui-widget-content {
- border: 1px solid #DDD;
-}
-
-#display-manage-price-details .ui-progressbar {
- height: 20px;
-}
-
-#display-manage-price-details .ui-progressbar .ui-progressbar-value {
- margin: 0px;
- background-color: #A40000;
- filter:alpha(opacity=70);
- -moz-opacity: 0.7;
- opacity: 0.7;
-}
-
-#display-manage-price-details .ui-progressbar .ui-progressbar-value.price-described {
- background-color: #4E9A06;
-}
-
-#display-manage-price-details #price-details-info {
- margin: 10px 0px;
-}
-
-#display-manage-price-details #details-progressbar {
- position: relative;
- width: 410px;
- display: inline-block;
-}
-
-#display-manage-price-details #progressbar-text {
- position: absolute;
- top: 5px;
- right: 7px;
- font-size: 11px;
-}
-
-#display-manage-price-details #progressbar-icon {
- display: inline-block;
- cursor: pointer;
-}
-
-#display-manage-price-details #details-progressbar .ui-corner-left,
-#display-manage-price-details #details-progressbar .ui-corner-right {
- -moz-border-radius-bottomleft: 0px;
- -moz-border-radius-bottomright: 0px;
- -moz-border-radius-topleft: 0px;
- -moz-border-radius-topright: 0px;
-}
-
diff --git a/public/stylesheets/product/categories-selection.scss b/public/stylesheets/product/categories-selection.scss
deleted file mode 100644
index 37298f9..0000000
--- a/public/stylesheets/product/categories-selection.scss
+++ /dev/null
@@ -1,61 +0,0 @@
-#category_form {
- border: 1px solid #AABB88;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- background: url(../images/ccc.gif); /* image ccc.gif from http://www.wannabegirl.org/translucent */
- padding: 10px 30px 20px 30px;
-}
-#categories_container_wrapper {
- overflow-x: scroll;
- margin: 10px 0 15px 0;
- padding: 5px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- background: url(../images/fff.gif); /* image fff.gif from http://www.wannabegirl.org/translucent */
- border: 1px solid #CCC;
- border-bottom: 0;
- position: relative;
-}
-.categories_container {
- min-height: 176px;
- display: inline-block;
- position: relative;
-}
-.categories_container .categories_container {
- position: absolute;
- top: 0;
- left: 100%;
-}
-.msie .categories_container .categories_container {
- left: auto;
-}
-.categories_container select {
- margin-right: 10px;
- height: 176px;
- font-size: 11px;
-}
-.controller-manage_products #categories_selection_actionbar input.button {
- height: 23px !important;
-}
-#save_and_continue_wrapper {
- position: relative;
-}
-#save_and_continue_disabled_tooltip {
- display: none;
- position: absolute;
- top: 30px;
- left: 0;
- min-width: 250px;
-}
-.msie #save_and_continue_disabled_tooltip {
- font-size: small;
-}
-#save_and_continue_wrapper #save_and_continue.disabled:hover + #save_and_continue_disabled_tooltip {
- display: block;
-}
-#hierarchy_navigation {
- min-height: 1.3em;
-}
-.msie #hierarchy_navigation {
- font-size: small;
-}
diff --git a/public/stylesheets/product/inputs.scss b/public/stylesheets/product/inputs.scss
deleted file mode 100644
index fed1e47..0000000
--- a/public/stylesheets/product/inputs.scss
+++ /dev/null
@@ -1,101 +0,0 @@
-
-#product-qualifiers, .input-list {
- padding: 0;
- margin-left: 0;
- position: relative;
-}
-.input-list-header {
- font-weight: bold;
- margin-top: 10px;
-}
-#content .main-block #product-inputs .input-list .input-item {
- text-align: left;
-}
-#content .main-block #product-qualifiers .product-qualifiers-item, #content .main-block #product-inputs .input-list .input-item, #content .main-block #show_product .input-list li, #content .main-block #show_product .ui-tabs ul .tab {
- list-style: none;
- list-style-image: none;
-}
-#product-qualifiers-list .icon-delete span {
- display: none;
-}
-.input-item {
- min-height: 40px;
- margin: 15px 0;
- position: relative;
- border: 1px solid transparent;
-}
-.msie .input-list .ui-state-highlight {
- height: 40px;
-}
-.input-item .button-bar {
- position: absolute;
- top: 0;
- right: 0;
- margin: 3px 0;
-}
-.input-details-form form {
- border: 1px dashed #EFEFEF;
- padding: 2px 0 5px 5px;
- margin-left: -5px;
-}
-.input-form-opened {
- border: 1px solid gray;
-}
-.input-form-closed {
- border: 0;
-}
-.input-details-form .amount-used {
- width: 70px;
- margin-right: 6px;
-}
-.input-details-form .price-per-unit {
- width: 110px;
-}
-.input-details-form table {
- width: auto;
-}
-#product-info-form tr:hover td, .input-details-form tr:hover td {
- background: none;
-}
-#product-info-form tr td, .input-details-form tr th, .input-details-form tr td {
- height: auto;
- border: none;
- padding: 2px 0;
-}
-#product-info-form tr .formlabel, .input-details-form tr .formlabel {
- max-width: 195px;
-}
-.input-details-form .selected-unit {
- padding: 0 2px;
-}
-.input-informations {
- padding: 5px 0 5px 5px;
-}
-.editing-input {
- border: 1px dotted #BBB;
-}
-.input-name {
- width: 240px;
-}
-.input-name, .input-details {
- display: inline-block;
-}
-.input-details {
- width: 190px;
-}
-.input-list-header .input-details {
- width: auto;
-}
-.add-input-details {
- position: absolute;
- left: 5px;
- top: 20px;
-}
-#content .main-block #product-inputs .input-list .remove-input, #content .main-block #product-inputs .input-list .edit-input {
- padding-top: 0;
- padding-bottom: 0;
-}
-.solidatiry-economy-icon {
- vertical-align: middle;
- padding: 0 3px;
-}
diff --git a/script/sample-categories b/script/sample-categories
index 14a4113..674b717 100755
--- a/script/sample-categories
+++ b/script/sample-categories
@@ -15,10 +15,6 @@ def new_state(parent, name)
save State.new(:name => name, :parent_id => parent ? parent.id : nil, :environment => $environment)
end
-def new_productcategory(parent, name)
- save ProductCategory.new(:name => name, :environment => $environment, :parent => parent)
-end
-
print "Creating categories: "
tematicas = new_category(nil, 'Temáticas', 1)
new_category(tematicas, 'Formação')
@@ -93,25 +89,3 @@ rs = new_state(sul, 'Rio Grande do Sul')
sc = new_state(sul, 'Santa Catarina')
done
-print "Creating product categories: "
-produtos = new_productcategory(nil, 'Produtos')
-alimentacao = new_productcategory(produtos, 'Alimentação')
-vegetais = new_productcategory(alimentacao, 'Vegetais')
-feijao = new_productcategory(vegetais, 'Feijão')
-arroz = new_productcategory(vegetais, 'Arroz')
-batata = new_productcategory(vegetais, 'Batata')
-carnes = new_productcategory(alimentacao, 'Carnes')
-boi = new_productcategory(carnes, 'Boi')
-frango = new_productcategory(carnes, 'Frango')
-vestuario = new_productcategory(produtos, 'Vestuário')
-camisetas = new_productcategory(vestuario, 'Camisetas')
-calcas = new_productcategory(vestuario, 'Calças')
-software_livre = new_productcategory(produtos, 'Software Livre')
-desenv = new_productcategory(software_livre, 'Desenvolvimento')
-capacitacao = new_productcategory(software_livre, 'Capacitação')
-admin_de_sistemas = new_productcategory(software_livre, 'Administração de sistemas')
-arte_digital = new_productcategory(software_livre, 'Arte Digital')
-arte_vetorial = new_productcategory(arte_digital, 'Arte Digital com Vetores')
-animacao = new_productcategory(arte_digital, 'Animação Digital')
-animacao_com_blender = new_productcategory(animacao, 'Animação Digital com Blender 3D')
-done
diff --git a/script/sample-data b/script/sample-data
index 2f0d661..0c4169c 100755
--- a/script/sample-data
+++ b/script/sample-data
@@ -6,5 +6,4 @@ id = ARGV.first || ''
system('./script/sample-categories', id)
system('./script/sample-profiles', id)
system('./script/sample-enterprises', id)
-system('./script/sample-products', id)
system('./script/sample-articles', id)
diff --git a/script/sample-products b/script/sample-products
deleted file mode 100755
index a9c31c2..0000000
--- a/script/sample-products
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env ruby
-require File.dirname(__FILE__) + '/../config/environment'
-include Noosfero::SampleDataHelper
-
-enterprises = $environment.enterprises
-categories = $environment.product_categories
-
-print "Creating products: "
-THINGS = %w[ Car House Bicycle Book Pen Computer Webcam ]
-COLORS = %w[ Black Red White Blue Green Purple ]
-for thing in THINGS
- for color in COLORS
- name = [color, thing].join(' ')
- rand(10).times do |i|
- profile = enterprises.sample
- next if profile.products.where(:name => name).first
- product = Product.new
- product.name = name
- product.profile_id = profile.id
- product.price = (i * 13.7)
- product.product_category_id = categories.sample.id
- save product
- end
- end
-end
-done
-
-print "Creating qualifiers and certifier: "
-QUALIFIERS = ['Organic', 'Free as in Freedom', 'Regional']
-CERTIFIERS = ['FBES', 'Colivre', 'Institute Paulo Freire', 'Fora do Eixo']
-for qualifier in QUALIFIERS
- save Qualifier.new(:name => qualifier, :environment => $environment)
-end
-for certifier in CERTIFIERS
- save Certifier.new(:name => certifier, :environment => $environment)
-end
-done
-
-print "Creating units: "
-[['Litre', 'Litres'], ['Kilo', 'Kilos'], ['Meter', 'Meters']].each do |unit|
- save Unit.new(:singular => unit[0], :plural => unit[1], :environment => $environment)
-end
-done
diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml
deleted file mode 100644
index b49c4eb..0000000
--- a/test/fixtures/products.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
-one:
- id: 1
-two:
- id: 2
diff --git a/test/functional/catalog_controller_test.rb b/test/functional/catalog_controller_test.rb
deleted file mode 100644
index c26df57..0000000
--- a/test/functional/catalog_controller_test.rb
+++ /dev/null
@@ -1,223 +0,0 @@
-require_relative "../test_helper"
-require 'catalog_controller'
-
-class CatalogControllerTest < ActionController::TestCase
- def setup
- @controller = CatalogController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
-
- Environment.default.enable('products_for_enterprises')
- @enterprise = fast_create(Enterprise, :name => 'My enterprise', :identifier => 'testent')
- @product_category = fast_create(ProductCategory)
- end
- attr_accessor :enterprise
-
- should 'not display for non-enterprises' do
- u = create_user('testinguser').person
- get :index, :profile => 'testinguser'
- assert_redirected_to :controller => "profile", :profile => 'testinguser', :action => 'index'
- end
-
- should 'display for enterprises' do
- get :index, :profile => 'testent'
- assert_response :success
- end
-
- should 'list products of enterprise' do
- get :index, :profile => @enterprise.identifier
- assert assigns(:products)
- end
-
- should 'paginate enterprise products list' do
- 1.upto(12).map do
- fast_create(Product, :profile_id => @enterprise.id)
- end
-
- assert_equal 12, @enterprise.products.count
- get :index, :profile => @enterprise.identifier
- assert_equal 6, assigns(:products).size
- assert_tag :a, :attributes => {:class => 'next_page'}
- end
-
- should 'not give access if environment do not let' do
- env = Environment.default
- env.disable('products_for_enterprises')
- env.save!
- ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent', :environment_id => env.id)
- get :index, :profile => ent.identifier
-
- assert_redirected_to :controller => 'profile', :action => 'index', :profile => ent.identifier
- end
-
- should 'not show product price when listing products if not informed' do
- prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category)
- get :index, :profile => @enterprise.identifier
- assert_no_tag :tag => 'span', :attributes => { :class => 'product-price with-discount' }, :content => /50.00/
- end
-
- should 'show product price when listing products if informed' do
- prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category)
- get :index, :profile => @enterprise.identifier
- assert_tag :tag => 'span', :attributes => { :class => 'product-price with-discount' }, :content => /50.00/
- end
-
- should 'show action moved to manage_products controller' do
- assert_raise ActionController::UrlGenerationError do
- get :show, :id => 1
- end
- end
-
- should 'include extra content supplied by plugins on catalog item extras' do
- class Plugin1 < Noosfero::Plugin
- def catalog_item_extras(product)
- proc {"This is Plugin1 speaking! ".html_safe}
- end
- end
-
- class Plugin2 < Noosfero::Plugin
- def catalog_item_extras(product)
- proc {"This is Plugin2 speaking! ".html_safe}
- end
- end
- Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
-
- product = fast_create(Product, :profile_id => @enterprise.id)
- environment = Environment.default
- environment.enable_plugin(Plugin1.name)
- environment.enable_plugin(Plugin2.name)
-
- get :index, :profile => @enterprise.identifier
-
- assert_tag :tag => 'span', :content => 'This is Plugin1 speaking!', :attributes => {:id => 'plugin1'}
- assert_tag :tag => 'span', :content => 'This is Plugin2 speaking!', :attributes => {:id => 'plugin2'}
- end
-
- should 'get categories of the right level' do
- pc1 = create(ProductCategory, :name => "PC1", :environment => @enterprise.environment)
- pc2 = create(ProductCategory, :name => "PC2", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc3 = create(ProductCategory, :name => "PC3", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc4 = create(ProductCategory, :name => "PC4", :environment => @enterprise.environment, :parent_id => pc2.id)
- p1 = fast_create(Product, :product_category_id => pc1.id, :profile_id => @enterprise.id)
- p2 = fast_create(Product, :product_category_id => pc2.id, :profile_id => @enterprise.id)
- p3 = fast_create(Product, :product_category_id => pc3.id, :profile_id => @enterprise.id)
- p4 = fast_create(Product, :product_category_id => pc4.id, :profile_id => @enterprise.id)
-
- get :index, :profile => @enterprise.identifier, :level => pc1.id
-
- assert_not_includes assigns(:categories), pc1
- assert_includes assigns(:categories), pc2
- assert_includes assigns(:categories), pc3
- assert_not_includes assigns(:categories), pc4
- end
-
- should 'filter products based on level selected' do
- pc1 = ProductCategory.create!(:name => "PC1", :environment => @enterprise.environment)
- pc2 = ProductCategory.create!(:name => "PC2", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc3 = ProductCategory.create!(:name => "PC3", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc4 = ProductCategory.create!(:name => "PC4", :environment => @enterprise.environment, :parent_id => pc2.id)
- p1 = fast_create(Product, :product_category_id => pc1.id, :profile_id => @enterprise.id)
- p2 = fast_create(Product, :product_category_id => pc2.id, :profile_id => @enterprise.id)
- p3 = fast_create(Product, :product_category_id => pc3.id, :profile_id => @enterprise.id)
- p4 = fast_create(Product, :product_category_id => pc4.id, :profile_id => @enterprise.id)
-
- get :index, :profile => @enterprise.identifier, :level => pc2.id
-
- assert_not_includes assigns(:products), p1
- assert_includes assigns(:products), p2
- assert_not_includes assigns(:products), p3
- assert_includes assigns(:products), p4
- end
-
- should 'get products ordered by availability, highlighted and then name' do
- p1 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Zebra', :available => true, :highlighted => true)
- p2 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Car', :available => true)
- p3 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Panda', :available => true)
- p4 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Pen', :available => false, :highlighted => true)
- p5 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Ball', :available => false)
- p6 = fast_create(Product, :profile_id => @enterprise.id, :name => 'Medal', :available => false)
-
- get :index, :profile => @enterprise.identifier
-
- assert_equal [p1,p2,p3,p4,p5,p6], assigns(:products)
- end
-
- should 'add highlighted CSS class around a highlighted product' do
- prod = @enterprise.products.create!(:name => 'Highlighted Product', :product_category => @product_category, :highlighted => true)
- get :index, :profile => @enterprise.identifier
- assert_tag :tag => 'li', :attributes => { :class => 'product highlighted' }, :content => /Highlighted Product/
- end
-
- should 'do not add highlighted CSS class around an ordinary product' do
- prod = @enterprise.products.create!(:name => 'Ordinary Product', :product_category => @product_category, :highlighted => false)
- get :index, :profile => @enterprise.identifier
- assert_no_tag :tag => 'li', :attributes => { :class => 'product highlighted' }, :content => /Ordinary Product/
- end
-
- should 'display star image in highlighted product' do
- prod = @enterprise.products.create!(:name => 'The Eyes Are The Light', :product_category => @product_category, :highlighted => true)
- get :index, :profile => @enterprise.identifier
- assert_tag :tag => 'img', :attributes => { :class => 'star', :src => /star.png/ }
- end
-
- should 'display categories on breadcrumb' do
- pc1 = create(ProductCategory, :name => "PC1", :environment => @enterprise.environment)
- pc2 = create(ProductCategory, :name => "PC2", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc3 = create(ProductCategory, :name => "PC3", :environment => @enterprise.environment, :parent_id => pc1.id)
- pc4 = create(ProductCategory, :name => "PC4", :environment => @enterprise.environment, :parent_id => pc2.id)
- p1 = fast_create(Product, :product_category_id => pc1.id, :profile_id => @enterprise.id)
- p2 = fast_create(Product, :product_category_id => pc2.id, :profile_id => @enterprise.id)
- p3 = fast_create(Product, :product_category_id => pc3.id, :profile_id => @enterprise.id)
- p4 = fast_create(Product, :product_category_id => pc4.id, :profile_id => @enterprise.id)
-
- get :index, :profile => @enterprise.identifier, :level => pc4.id
-
- assert_tag :tag => 'div', :attributes => {:id => 'breadcrumb'}, :descendant => {:tag => 'a', :attributes => {:href => /level=#{pc1.id}/}}
- assert_tag :tag => 'div', :attributes => {:id => 'breadcrumb'}, :descendant => {:tag => 'a', :attributes => {:href => /level=#{pc2.id}/}}
- assert_tag :tag => 'div', :attributes => {:id => 'breadcrumb'}, :descendant => {:tag => 'strong', :content => pc4.name}
- assert_no_tag :tag => 'div', :attributes => {:id => 'breadcrumb'}, :descendant => {:tag => 'a', :attributes => {:href => /level=#{pc3.id}/}}
- end
-
- should 'add product status on the class css' do
- category = create(ProductCategory, :name => "Cateogry", :environment => @enterprise.environment)
- p1 = fast_create(Product, :product_category_id => category.id, :profile_id => @enterprise.id, :highlighted => true)
- p2 = fast_create(Product, :product_category_id => category.id, :profile_id => @enterprise.id, :available => false)
-
- get :index, :profile => @enterprise.identifier
-
- assert_tag :tag => 'li', :attributes => {:id => "product-#{p1.id}", :class => /highlighted/}
- assert_tag :tag => 'li', :attributes => {:id => "product-#{p2.id}", :class => /not-available/}
- end
-
- should 'sort categories by name' do
- environment = @enterprise.environment
- environment.categories.destroy_all
- pc1 = create(ProductCategory, :name => "Drinks", :environment => environment)
- pc2 = create(ProductCategory, :name => "Bananas", :environment => environment)
- pc3 = create(ProductCategory, :name => "Sodas", :environment => environment)
- pc4 = create(ProductCategory, :name => "Pies", :environment => environment)
- p1 = fast_create(Product, :product_category_id => pc1.id, :profile_id => @enterprise.id)
- p2 = fast_create(Product, :product_category_id => pc2.id, :profile_id => @enterprise.id)
- p3 = fast_create(Product, :product_category_id => pc3.id, :profile_id => @enterprise.id)
- p4 = fast_create(Product, :product_category_id => pc4.id, :profile_id => @enterprise.id)
-
- get :index, :profile => @enterprise.identifier
-
- assert_equal [pc2, pc1, pc4, pc3], assigns(:categories)
- end
-
- should 'use price_detail name instead of production_cost name straight' do
- p1 = fast_create(Product, :product_category_id => @product_category.id, :profile_id => @enterprise.id)
- p2 = fast_create(Product, :product_category_id => @product_category.id, :profile_id => @enterprise.id)
- Product.any_instance.stubs(:price_described?).returns(true)
- production_cost = fast_create(ProductionCost)
- pd1 = create(PriceDetail, :product => p1, :production_cost_id => production_cost.id)
- pd2 = create(PriceDetail, :product => p2)
-
- get :index, :profile => @enterprise.identifier
-
- assert_tag :tag => 'div', :attributes => {:class => 'search-product-input-name'}, :content => production_cost.name
- assert_tag :tag => 'div', :attributes => {:class => 'search-product-input-name'}, :content => 'Other costs'
- end
-
-end
diff --git a/test/functional/categories_controller_test.rb b/test/functional/categories_controller_test.rb
index b96b4cb..0d20e09 100644
--- a/test/functional/categories_controller_test.rb
+++ b/test/functional/categories_controller_test.rb
@@ -44,12 +44,6 @@ class CategoriesControllerTest < ActionController::TestCase
get :new
end
- def test_new_product_category
- cat = ProductCategory.new
- ProductCategory.expects(:new).returns(cat)
- get :new, :type => 'ProductCategory'
- end
-
def test_new_save
assert_difference 'Category.count' do
post :new, :category => { :name => 'a new category' }
@@ -137,22 +131,20 @@ class CategoriesControllerTest < ActionController::TestCase
assert_tag :tag => 'input', :attributes => { :name => "category[display_color]" }
end
- should 'not list regions and product categories' do
+ should 'not list regions' do
Environment.default.categories.destroy_all
c = create(Category, :name => 'Regular category', :environment => Environment.default)
- p = create(ProductCategory, :name => 'Product category', :environment => Environment.default)
r = create(Region, :name => 'Some region', :environment => Environment.default)
get :index
assert_equal [c], assigns(:categories)
- assert_equal [p], assigns(:product_categories)
assert_equal [r], assigns(:regions)
end
should 'use parent\'s type to determine subcategory\'s type' do
- parent = create(ProductCategory, :name => 'Sample category', :environment => Environment.default)
+ parent = create(Region, name: 'Sample category', environment: Environment.default)
post :new, :parent_id => parent.id, :parent_type => parent.class.name, :category => {:name => 'Subcategory'}
- sub = ProductCategory.find_by(name: 'Subcategory')
+ sub = Region.find_by_name('Subcategory')
assert_equal parent.class, sub.class
end
diff --git a/test/functional/cms_controller_test.rb b/test/functional/cms_controller_test.rb
index 89246cc..5851d54 100644
--- a/test/functional/cms_controller_test.rb
+++ b/test/functional/cms_controller_test.rb
@@ -741,18 +741,6 @@ class CmsControllerTest < ActionController::TestCase
assert_tag :input, :attributes => { :id => 'article_link' }
end
- should 'not make enterprise homepage available to person' do
- @controller.stubs(:profile).returns(profile)
- @controller.stubs(:user).returns(profile)
- assert_not_includes available_article_types, EnterpriseHomepage
- end
-
- should 'make enterprise homepage available to enterprises' do
- @controller.stubs(:profile).returns(fast_create(Enterprise, :name => 'test_ent', :identifier => 'test_ent'))
- @controller.stubs(:user).returns(profile)
- assert_includes available_article_types, EnterpriseHomepage
- end
-
should 'update categories' do
env = Environment.default
top = env.categories.create!(:display_in_menu => true, :name => 'Top-Level category')
diff --git a/test/functional/environment_design_controller_test.rb b/test/functional/environment_design_controller_test.rb
index f411be5..76f9407 100644
--- a/test/functional/environment_design_controller_test.rb
+++ b/test/functional/environment_design_controller_test.rb
@@ -3,7 +3,7 @@ require 'environment_design_controller'
class EnvironmentDesignControllerTest < ActionController::TestCase
- ALL_BLOCKS = [ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
+ ALL_BLOCKS = [ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
def setup
@controller = EnvironmentDesignController.new
@@ -122,16 +122,6 @@ class EnvironmentDesignControllerTest < ActionController::TestCase
assert_tag :tag => 'input', :attributes => { :id => 'block_limit' }
end
- should 'be able to edit SellersSearchBlock' do
- login_as(create_admin_user(Environment.default))
- b = SellersSearchBlock.create!
- e = Environment.default
- e.boxes.create!
- e.boxes.first.blocks << b
- get :edit, :id => b.id
- assert_tag :tag => 'input', :attributes => { :id => 'block_title' }
- end
-
should 'be able to edit FeedReaderBlock' do
login_as(create_admin_user(Environment.default))
b = FeedReaderBlock.create!
diff --git a/test/functional/manage_products_controller_test.rb b/test/functional/manage_products_controller_test.rb
deleted file mode 100644
index fb71f7a..0000000
--- a/test/functional/manage_products_controller_test.rb
+++ /dev/null
@@ -1,505 +0,0 @@
-require_relative "../test_helper"
-require 'manage_products_controller'
-
-class ManageProductsControllerTest < ActionController::TestCase
- all_fixtures
- def setup
- @controller = ManageProductsController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- @enterprise = fast_create(Enterprise, :name => 'teste', :identifier => 'test_ent')
- @user = create_user_with_permission('test_user', 'manage_products', @enterprise)
- @environment = @enterprise.environment
- @environment.enable('products_for_enterprises')
- @product_category = fast_create(ProductCategory)
- login_as :test_user
- end
-
- should "not have permission" do
- u = create_user('user_test')
- login_as :user_test
- get 'index', :profile => @enterprise.identifier
- assert :success
- assert_template 'shared/access_denied'
- end
-
- should "get index" do
- get 'index', :profile => @enterprise.identifier
- assert_response :success
- assert assigns(:products)
- end
-
- should "get new form" do
- get 'new', :profile => @enterprise.identifier
- assert_response :success
- assert assigns(:product)
- assert_template 'new'
- assert_tag :tag => 'form', :attributes => { :action => /new/ }
- end
-
- should "create new product" do
- assert_difference 'Product.count' do
- post 'new', :profile => @enterprise.identifier, :product => {:name => 'test product'}, :selected_category_id => @product_category.id
- assert assigns(:product)
- refute assigns(:product).new_record?
- end
- end
-
- should "not create invalid product" do
- assert_no_difference 'Product.count' do
- post 'new', :profile => @enterprise.identifier, :product => {:name => 'test product'}
- assert_response :success
- assert assigns(:product)
- assert assigns(:product).new_record?
- end
- end
-
- should "get edit name form" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'name'
- assert_response :success
- assert assigns(:product)
- assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=name/ }
- end
-
- should "get edit info form" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'info'
- assert_response :success
- assert assigns(:product)
- assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=info/ }
- end
-
- should "get edit image form" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'image'
- assert_response :success
- assert assigns(:product)
- assert_tag :tag => 'form', :attributes => { :action => /myprofile\/#{@enterprise.identifier}\/manage_products\/edit\/#{product.id}\?field=image/ }
- end
-
- should "edit product name" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- post :edit, :profile => @enterprise.identifier, :product => {:name => 'new test product'}, :id => product.id, :field => 'name'
- assert_response :success
- assert assigns(:product)
- refute assigns(:product).new_record?
- assert_equal product, Product.find_by(name: 'new test product')
- end
-
- should "edit product description" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id, :description => 'My product is very good')
- post :edit, :profile => @enterprise.identifier, :product => {:description => 'A very good product!'}, :id => product.id, :field => 'info'
- assert_response :success
- assert assigns(:product)
- refute assigns(:product).new_record?
- assert_equal 'A very good product!', Product.find_by(name: 'test product').description
- end
-
- should "edit product image" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- post :edit, :profile => @enterprise.identifier, :product => { :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') } }, :id => product.id, :field => 'image'
- assert_response :success
- assert assigns(:product)
- refute assigns(:product).new_record?
- assert_equal 'rails.png', Product.find_by(name: 'test product').image.filename
- end
-
- should "not edit to invalid parameters" do
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- post 'edit_category', :profile => @enterprise.identifier, :selected_category_id => nil, :id => product.id
- assert_response :success
- assert_template 'shared/_dialog_error_messages'
- end
-
- should "not crash if product has no category" do
- product = fast_create(Product, :profile_id => @enterprise.id)
- assert_nothing_raised do
- post 'edit_category', :profile => @enterprise.identifier, :id => product.id
- end
- end
-
- should "destroy product" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- assert_difference 'Product.count', -1 do
- post 'destroy', :profile => @enterprise.identifier, :id => product.id
- assert_response :redirect
- assert_redirected_to :action => 'index'
- assert assigns(:product)
- refute Product.find_by(name: 'test product')
- end
- end
-
- should "fail to destroy product" do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- Product.any_instance.stubs(:destroy).returns(false)
- assert_no_difference 'Product.count' do
- post 'destroy', :profile => @enterprise.identifier, :id => product.id
- assert_response :redirect
- assert_redirected_to :controller => "manage_products", :profile => @enterprise.identifier, :action => 'show', :id => product.id
- assert assigns(:product)
- assert Product.find_by(name: 'test product')
- end
- end
-
- should 'show categories selection' do
- category1 = fast_create(ProductCategory, :name => 'Category 1')
- category2 = fast_create(ProductCategory, :name => 'Category 2', :parent_id => category1.id)
- category3 = fast_create(ProductCategory, :name => 'Category 3', :parent_id => category2.id)
- get :new, :profile => @enterprise.identifier
- assert_tag :tag => 'select', :attributes => { :id => 'category_id' }, :descendant => { :tag => 'option', :content => category1.name }
- end
-
- should "create new product categorized" do
- category1 = fast_create(ProductCategory, :name => 'Category 1')
- category2 = fast_create(ProductCategory, :name => 'Category 2', :parent_id => category1)
- assert_difference 'Product.count' do
- post 'new', :profile => @enterprise.identifier, :product => { :name => 'test product' }, :selected_category_id => category2.id
- assert_equal category2, assigns(:product).product_category
- end
- end
-
- should 'not create a new product with an invalid category' do
- category1 = fast_create(Category, :name => 'Category 1')
- category2 = fast_create(Category, :name => 'Category 2', :parent_id => category1)
- assert_raise ActiveRecord::AssociationTypeMismatch do
- post 'new', :profile => @enterprise.identifier, :product => { :name => 'test product' }, :selected_category_id => category2.id
- end
- end
-
- should 'filter html from name of product' do
- category = fast_create(ProductCategory, :name => 'Category 1')
- post 'new', :profile => @enterprise.identifier, :product => { :name => "name bold " }, :selected_category_id => category.id
- assert_sanitized assigns(:product).name
- end
-
- should 'filter html with white list from description of product' do
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- post 'edit', :profile => @enterprise.identifier, :id => product.id, :field => 'info', :product => { :name => 'name', :description => "descr bold " }
- assert_equal "descr bold ", assigns(:product).description
- end
-
- should 'not let users in if environment do not let' do
- env = Environment.default
- env.disable('products_for_enterprises')
- env.save!
- @enterprise.environment = env
- @enterprise.save!
- get :index, :profile => @enterprise.identifier
-
- assert_template 'not_found'
- end
-
- should 'show top level product categories for the user to choose' do
- pc1 = fast_create(ProductCategory, :name => 'test_category1')
- pc2 = fast_create(ProductCategory, :name => 'test_category2')
-
- get :new, :profile => @enterprise.identifier
-
- assert_equivalent ProductCategory.top_level_for(pc1.environment), assigns(:categories)
- end
-
- should 'increase level while navigate on hierarchy categories' do
- category_level0 = fast_create(ProductCategory, :name => 'Products', :environment_id => @environment.id)
- category_level1 = fast_create(ProductCategory, :parent_id => category_level0.id, :name => 'Shoes', :environment_id => @environment.id)
- category_level2 = fast_create(ProductCategory, :parent_id => category_level1.id, :name => 'Athletic Shoes', :environment_id => @environment.id)
-
- get :categories_for_selection, :profile => @enterprise.identifier, :category_id => category_level0.id
- assert_equal 0, assigns(:level)
-
- get :categories_for_selection, :profile => @enterprise.identifier, :category_id => category_level1.id
- assert_equal 1, assigns(:level)
-
- get :categories_for_selection, :profile => @enterprise.identifier, :category_id => category_level2.id
- assert_equal 2, assigns(:level)
- end
-
- should 'remember the selected category' do
- category0 = fast_create(ProductCategory, :name => 'Products', :environment_id => @environment.id)
- category1 = fast_create(ProductCategory, :name => 'Shoes', :environment_id => @environment.id)
-
- get :categories_for_selection, :profile => @enterprise.identifier, :category_id => category0.id
- assert_equal category0, assigns(:category)
-
- get :categories_for_selection, :profile => @enterprise.identifier, :category_id => category1.id
- assert_equal category1, assigns(:category)
- end
-
- should 'list top level categories when has no category_id' do
- get :categories_for_selection, :profile => @enterprise.identifier
-
- assert_equal ProductCategory.top_level_for(@environment), assigns(:categories)
- end
-
- should 'render dialog_error_messages template for invalid product' do
- post :new, :profile => @enterprise.identifier, :product => { :name => 'Invalid product' }
- assert_template 'shared/_dialog_error_messages'
- end
-
- should 'render redirect_via_javascript template after save' do
- assert_difference 'Product.count' do
- post :new, :profile => @enterprise.identifier, :product => { :name => 'Invalid product' }, :selected_category_id => @product_category.id
- assert_template 'shared/_redirect_via_javascript'
- end
- end
-
- should 'show product of enterprise' do
- prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category)
- get :show, :id => prod.id, :profile => @enterprise.identifier
- assert_tag :tag => 'h2', :content => /#{prod.name}/
- end
-
- should 'link back to index from product show' do
- enterprise = create(Enterprise, :name => 'test_enterprise_1', :identifier => 'test_enterprise_1', :environment => Environment.default)
- prod = enterprise.products.create!(:name => 'Product test', :product_category => @product_category)
- get :show, :id => prod.id, :profile => enterprise.identifier
- assert_tag({
- :tag => 'div',
- :attributes => {
- :class => /main-block/
- },
- :descendant => {
- :tag => 'a',
- :attributes => {
- :href => "/catalog/#{enterprise.identifier}",
- },
- :content => /Back to the product listing/
- }
- })
- end
-
- should 'not show product price when showing product if not informed' do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_no_tag :tag => 'span', :attributes => { :class => 'product_price' }, :content => /Price:/
- end
-
- should 'show product price when showing product if unit was informed' do
- product = fast_create(Product, :name => 'test product', :price => 50.00, :unit_id => fast_create(Unit).id, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/
- assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
- end
-
- should 'show product price when showing product if discount was informed' do
- product = fast_create(Product, :name => 'test product', :price => 50.00, :unit_id => fast_create(Unit).id, :discount => 3.50, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /List price:/
- assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
- assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /On sale:/
- assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 46.50'
- end
-
- should 'show product price when showing product if unit not informed' do
- product = fast_create(Product, :name => 'test product', :price => 50.00, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'span', :attributes => { :class => 'field-name' }, :content => /Price:/
- assert_tag :tag => 'span', :attributes => { :class => 'field-value' }, :content => '$ 50.00'
- end
-
- should 'display button to add input when product has no input' do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'div', :attributes => { :id => 'display-add-input-button'},
- :descendant => {:tag => 'a', :attributes => { :href => "/myprofile/#{@enterprise.identifier}/manage_products/add_input/#{product.id}", :id => 'add-input-button'}, :content => 'Add the inputs or raw material used by this product'}
- end
-
- should 'has instance of input list when showing product' do
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
- assert_equal [], assigns(:inputs)
- end
-
- should 'remove input of a product' do
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id)
- assert_equal [input], product.inputs
-
- post :remove_input, :id => input.id, :profile => @enterprise.identifier
- product.reload
- assert_equal [], product.inputs
- end
-
- should 'save inputs order' do
- product = fast_create(Product, :profile_id => @enterprise.id)
- first = Input.create!(:product => product, :product_category => fast_create(ProductCategory))
- second = Input.create!(:product => product, :product_category => fast_create(ProductCategory))
- third = Input.create!(:product => product, :product_category => fast_create(ProductCategory))
-
- assert_equal [first, second, third], product.inputs(true)
-
- get :order_inputs, :profile => @enterprise.identifier, :id => product, :input => [second.id, third.id, first.id]
- assert_template nil
-
- assert_equal [second, third, first], product.inputs(true)
- end
-
- should 'render partial certifiers for selection' do
- xhr :get, :certifiers_for_selection, :profile => @enterprise.identifier
- assert_template '_certifiers_for_selection'
- end
-
- should 'not list all the products of enterprise' do
- @enterprise.products = []
- 1.upto(12) do |n|
- fast_create(Product, :name => "test product_#{n}", :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- end
- get :index, :profile => @enterprise.identifier
- assert_equal 10, assigns(:products).size
- end
-
- should 'paginate the manage products list of enterprise' do
- @enterprise.products = []
- 1.upto(12) do |n|
- fast_create(Product, :name => "test product_#{n}", :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- end
- get :index, :profile => @enterprise.identifier
- assert_tag :tag => 'a', :attributes => { :rel => 'next', :href => "/myprofile/#{@enterprise.identifier}/manage_products?page=2" }
-
- get :index, :profile => @enterprise.identifier, :page => 2
- assert_equal 2, assigns(:products).size
- end
-
- should 'display tabs even if description and inputs are empty and user is allowed' do
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }
- end
-
- should 'not display tabs if description and inputs are empty and user is not allowed' do
- create_user('foo')
-
- login_as 'foo'
-
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_no_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }
- end
-
- should 'not display tabs if description and inputs are empty and user is not logged in' do
- logout
-
- product = fast_create(Product, :name => 'test product', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_no_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }
- end
-
- should 'display only description tab if inputs are empty and user is not allowed' do
- create_user('foo')
-
- login_as 'foo'
- product = fast_create(Product, :description => 'This product is very good', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- get :show, :id => product.id, :profile => @enterprise.identifier
- assert_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#product-description'}, :content => 'Description'}
- assert_no_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#inputs'}, :content => 'Inputs and raw material'}
- end
-
- should 'display only inputs tab if description is empty and user is not allowed' do
- create_user 'foo'
-
- login_as 'foo'
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id)
-
- get :show, :id => product.id, :profile => @enterprise.identifier
- assert_no_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#product-description'}, :content => 'Description'}
- assert_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#product-inputs'}, :content => 'Inputs and raw material'}
- end
-
- should 'display tabs if description and inputs are not empty and user is not allowed' do
- create_user('foo')
-
- login_as 'foo'
- product = fast_create(Product, :description => 'This product is very good', :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- input = fast_create(Input, :product_id => product.id, :product_category_id => @product_category.id)
-
- get :show, :id => product.id, :profile => @enterprise.identifier
- assert_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#product-description'}, :content => 'Description'}
- assert_tag :tag => 'div', :attributes => { :id => "product-#{product.id}-tabs" }, :descendant => {:tag => 'a', :attributes => {:href => '#product-inputs'}, :content => 'Inputs and raw material'}
- end
-
- should 'include extra content supplied by plugins on products info extras' do
- class TestProductInfoExtras1Plugin < Noosfero::Plugin
- def product_info_extras(p)
- proc {"This is Plugin1 speaking! ".html_safe}
- end
- end
- class TestProductInfoExtras2Plugin < Noosfero::Plugin
- def product_info_extras(p)
- proc { "This is Plugin2 speaking! ".html_safe }
- end
- end
-
- product = fast_create(Product, :profile_id => @enterprise.id)
-
- Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestProductInfoExtras1Plugin.new, TestProductInfoExtras2Plugin.new])
-
- get :show, :id => product.id, :profile => @enterprise.identifier
-
- assert_tag :tag => 'span', :content => 'This is Plugin1 speaking!', :attributes => {:id => 'plugin1'}
- assert_tag :tag => 'span', :content => 'This is Plugin2 speaking!', :attributes => {:id => 'plugin2'}
- end
-
- should 'not allow product creation for profiles that can\'t do it' do
- class SpecialEnterprise < Enterprise
- def create_product?
- false
- end
- end
- enterprise = SpecialEnterprise.create!(:identifier => 'special-enterprise', :name => 'Special Enterprise')
- get 'new', :profile => enterprise.identifier
- assert_response 403
- end
-
- should 'remove price detail of a product' do
- product = fast_create(Product, :profile_id => @enterprise.id, :product_category_id => @product_category.id)
- cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment')
- detail = product.price_details.create(:production_cost_id => cost.id, :price => 10)
-
- assert_equal [detail], product.price_details
-
- post :remove_price_detail, :id => detail.id, :product => product, :profile => @enterprise.identifier
- product.reload
- assert_equal [], product.price_details
- end
-
- should 'create a production cost for enterprise' do
- get :create_production_cost, :profile => @enterprise.identifier, :id => 'Taxes'
-
- assert_equal ['Taxes'], Enterprise.find(@enterprise.id).production_costs.map(&:name)
- resp = ActiveSupport::JSON.decode(@response.body)
- assert_equal 'Taxes', resp['name']
- assert resp['id'].kind_of?(Integer)
- assert resp['ok']
- assert_nil resp['error_msg']
- end
-
- should 'display error if production cost has no name' do
- get :create_production_cost, :profile => @enterprise.identifier
-
- resp = ActiveSupport::JSON.decode(@response.body)
- assert_nil resp['name']
- assert_nil resp['id']
- refute resp['ok']
- assert_match /blank/, resp['error_msg']
- end
-
- should 'display error if name of production cost is too long' do
- get :create_production_cost, :profile => @enterprise.identifier, :id => 'a'*60
-
- resp = ActiveSupport::JSON.decode(@response.body)
- assert_nil resp['name']
- assert_nil resp['id']
- refute resp['ok']
- assert_match /too long/, resp['error_msg']
- end
-
-end
diff --git a/test/functional/map_balloon_controller_test.rb b/test/functional/map_balloon_controller_test.rb
index 7001257..bb607e8 100644
--- a/test/functional/map_balloon_controller_test.rb
+++ b/test/functional/map_balloon_controller_test.rb
@@ -12,13 +12,6 @@ class MapBalloonControllerTest < ActionController::TestCase
login_as(@profile.identifier)
end
- should 'find product to show' do
- prod = create(Product, :name => 'Product1', :product_category_id => fast_create(ProductCategory).id,
- :profile_id => fast_create(Enterprise).id)
- get :product, :id => prod.id
- assert_equal prod, assigns(:product)
- end
-
should 'find person to show' do
pers = create(Person, :name => 'Person1', :user_id => fast_create(User).id, :identifier => 'pers1')
get :person, :id => pers.id
diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb
index 8c6d021..0bd8275 100644
--- a/test/functional/profile_controller_test.rb
+++ b/test/functional/profile_controller_test.rb
@@ -5,7 +5,6 @@ class ProfileControllerTest < ActionController::TestCase
self.default_params = {profile: 'testuser'}
def setup
- Environment.default.enable('products_for_enterprises')
@profile = create_user('testuser').person
end
attr_reader :profile
@@ -231,29 +230,6 @@ class ProfileControllerTest < ActionController::TestCase
assert_no_match /Add friend/, @response.body
end
- should 'display "Products" link for enterprise' do
- ent = fast_create(Enterprise, :name => 'my test enterprise', :identifier => 'my-test-enterprise', :enabled => false)
- product = fast_create(Product, :profile_id => ent.id)
-
- get :index, :profile => 'my-test-enterprise'
- assert_tag :tag => 'a', :attributes => { :href => '/catalog/my-test-enterprise'}, :content => /Products\/Services/
- end
-
- should 'not display "Products" link for enterprise if environment do not let' do
- env = Environment.default
- env.disable('products_for_enterprises')
- ent = fast_create(Enterprise, :name => 'my test enterprise', :identifier => 'my-test-enterprise', :enabled => false, :environment_id => env.id)
-
- get :index, :profile => 'my-test-enterprise'
- assert_no_tag :tag => 'a', :attributes => { :href => '/catalog/my-test-enterprise'}, :content => /Products\/Services/
- end
-
-
- should 'not display "Products" link for people' do
- get :index, :profile => 'ze'
- assert_no_tag :tag => 'a', :attributes => { :href => '/catalog/my-test-enterprise'}, :content => /Products\/Services/
- end
-
should 'list top level articles in sitemap' do
get :sitemap, :profile => 'testuser'
assert_equal @profile.top_level_articles, assigns(:articles)
diff --git a/test/functional/profile_design_controller_test.rb b/test/functional/profile_design_controller_test.rb
index 809b015..6fb20f4 100644
--- a/test/functional/profile_design_controller_test.rb
+++ b/test/functional/profile_design_controller_test.rb
@@ -1,5 +1,4 @@
-require_relative "../test_helper"
-require 'profile_design_controller'
+require_relative '../test_helper'
class ProfileDesignControllerTest < ActionController::TestCase
@@ -7,8 +6,7 @@ class ProfileDesignControllerTest < ActionController::TestCase
PERSON_BLOCKS = COMMOM_BLOCKS + [ FavoriteEnterprisesBlock, CommunitiesBlock, EnterprisesBlock ]
PERSON_BLOCKS_WITH_BLOG = PERSON_BLOCKS + [BlogArchivesBlock]
- ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, FeaturedProductsBlock, FansBlock, ProductCategoriesBlock]
- ENTERPRISE_BLOCKS_WITH_PRODUCTS_ENABLE = ENTERPRISE_BLOCKS + [ProductsBlock]
+ ENTERPRISE_BLOCKS = COMMOM_BLOCKS + [DisabledEnterpriseMessageBlock, FansBlock]
attr_reader :holder
def setup
@@ -60,8 +58,6 @@ class ProfileDesignControllerTest < ActionController::TestCase
@controller.stubs(:boxes_holder).returns(holder)
login_as 'designtestuser'
-
- @product_category = fast_create(ProductCategory)
end
attr_reader :profile
@@ -309,50 +305,6 @@ class ProfileDesignControllerTest < ActionController::TestCase
assert_response :forbidden
end
- should 'be able to edit ProductsBlock' do
- block = ProductsBlock.new
-
- enterprise = fast_create(Enterprise, :name => "test", :identifier => 'testenterprise')
- enterprise.boxes << Box.new
- p1 = enterprise.products.create!(:name => 'product one', :product_category => @product_category)
- p2 = enterprise.products.create!(:name => 'product two', :product_category => @product_category)
- enterprise.boxes.first.blocks << block
- enterprise.add_admin(holder)
-
- enterprise.blocks(true)
- @controller.stubs(:boxes_holder).returns(enterprise)
- login_as('designtestuser')
-
- get :edit, :profile => 'testenterprise', :id => block.id
-
- assert_response :success
- assert_tag :tag => 'input', :attributes => { :name => "block[product_ids][]", :value => p1.id.to_s }
- assert_tag :tag => 'input', :attributes => { :name => "block[product_ids][]", :value => p2.id.to_s }
- end
-
- should 'be able to save ProductsBlock' do
- block = ProductsBlock.new
-
- enterprise = fast_create(Enterprise, :name => "test", :identifier => 'testenterprise')
- enterprise.boxes << Box.new
- p1 = enterprise.products.create!(:name => 'product one', :product_category => @product_category)
- p2 = enterprise.products.create!(:name => 'product two', :product_category => @product_category)
- enterprise.boxes.first.blocks << block
- enterprise.add_admin(holder)
-
- enterprise.blocks(true)
- @controller.stubs(:boxes_holder).returns(enterprise)
- login_as('designtestuser')
-
- post :save, :profile => 'testenterprise', :id => block.id, :block => { :product_ids => [p1.id.to_s, p2.id.to_s ] }
-
- assert_response :redirect
-
- block.reload
- assert_equal [p1.id, p2.id], block.product_ids
-
- end
-
should 'display back to control panel button' do
get :index, :profile => 'designtestuser'
assert_tag :tag => 'a', :content => 'Back to control panel'
@@ -364,19 +316,6 @@ class ProfileDesignControllerTest < ActionController::TestCase
assert_equal assigns(:available_blocks), [ArticleBlock, TagsBlock]
end
- should 'not allow products block if environment do not let' do
- env = Environment.default
- env.disable('products_for_enterprises')
- env.save!
- ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent', :environment_id => env.id)
- person = create_user_with_permission('test_user', 'edit_profile_design', ent)
- login_as(person.user.login)
-
- get :index, :profile => 'test_ent'
-
- assert_no_tag :tag => 'div', :attributes => { 'data-block-type' => 'ProductsBlock' }
- end
-
should 'create back link to profile control panel' do
p = Profile.create!(:name => 'test_profile', :identifier => 'test_profile')
@@ -484,30 +423,12 @@ class ProfileDesignControllerTest < ActionController::TestCase
environment = mock
profile.stubs(:environment).returns(environment)
environment.stubs(:enabled?).returns(true)
- environment.stubs(:enabled?).with('products_for_enterprises').returns(false)
@controller.stubs(:profile).returns(profile)
@controller.stubs(:user).returns(profile)
Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([])
assert_equal [], @controller.available_blocks - ENTERPRISE_BLOCKS
end
- should 'the enterprise with products for enterprise enable blocks are all available' do
- profile = mock
- profile.stubs(:has_members?).returns(false)
- profile.stubs(:person?).returns(false)
- profile.stubs(:community?).returns(true)
- profile.stubs(:enterprise?).returns(true)
- profile.stubs(:has_blog?).returns(false)
- profile.stubs(:is_admin?).with(anything).returns(false)
- environment = mock
- profile.stubs(:environment).returns(environment)
- environment.stubs(:enabled?).returns(true)
- @controller.stubs(:profile).returns(profile)
- @controller.stubs(:user).returns(profile)
- Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([])
- assert_equal [], @controller.available_blocks - ENTERPRISE_BLOCKS_WITH_PRODUCTS_ENABLE
- end
-
should 'allow admins to add RawHTMLBlock' do
profile.stubs(:is_admin?).returns(true)
@controller.stubs(:user).returns(profile)
diff --git a/test/functional/profile_editor_controller_test.rb b/test/functional/profile_editor_controller_test.rb
index 47f6d18..c25cf98 100644
--- a/test/functional/profile_editor_controller_test.rb
+++ b/test/functional/profile_editor_controller_test.rb
@@ -579,20 +579,6 @@ class ProfileEditorControllerTest < ActionController::TestCase
assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{enterprise.identifier}/profile_editor/header_footer" }
end
- should 'not list the manage products button if the environment disabled it' do
- env = Environment.default
- env.disable('products_for_enterprises')
- env.save!
- ent = fast_create(Enterprise)
-
- u = create_user_with_permission('test_user', 'edit_profile', ent)
- login_as('test_user')
-
- get :index, :profile => ent.identifier
-
- assert_no_tag :tag => 'span', :content => 'Manage Products and Services'
- end
-
should 'display categories if environment disable_categories disabled' do
Environment.any_instance.stubs(:enabled?).with(anything).returns(false)
get :edit, :profile => profile.identifier
@@ -1131,46 +1117,6 @@ class ProfileEditorControllerTest < ActionController::TestCase
assert_response :success
end
- should 'display field to choose number of products if enterprise and enabled on environment' do
- enterprise = fast_create(Enterprise)
- enterprise.environment.enable('products_for_enterprises')
- get :edit, :profile => enterprise.identifier
- assert_tag :tag => 'div', :descendant => { :tag => 'h2', :content => 'Products/Services catalog' }
- assert_tag :tag => 'div',
- :attributes => { :class => 'formfield type-text' },
- :descendant => {:tag => 'input', :attributes => {:id => 'profile_data_products_per_catalog_page'} }
- end
-
- should 'not display field to choose number of products if enterprise but disabled on environment' do
- enterprise = fast_create(Enterprise)
- enterprise.environment.disable('products_for_enterprises')
- get :edit, :profile => enterprise.identifier
- assert_no_tag :tag => 'div', :descendant => { :tag => 'h2', :content => 'Products/Services catalog' }
- assert_no_tag :tag => 'div',
- :attributes => { :class => 'formfield type-text' },
- :descendant => {:tag => 'input', :attributes => {:id => 'profile_data_products_per_catalog_page'} }
- end
-
- should 'not display field to choose number of products if enabled on environment but not enterprise' do
- community = fast_create(Community)
- community.environment.enable('products_for_enterprises')
- get :edit, :profile => community.identifier
- assert_no_tag :tag => 'div', :descendant => { :tag => 'h2', :content => 'Products/Services catalog' }
- assert_no_tag :tag => 'div',
- :attributes => { :class => 'formfield type-text' },
- :descendant => {:tag => 'input', :attributes => {:id => 'profile_data_products_per_catalog_page'} }
- end
-
- should 'not display field to choose number of products if disabled on environment and not enterprise' do
- community = fast_create(Community)
- community.environment.disable('products_for_enterprises')
- get :edit, :profile => community.identifier
- assert_no_tag :tag => 'div', :descendant => { :tag => 'h2', :content => 'Products/Services catalog' }
- assert_no_tag :tag => 'div',
- :attributes => { :class => 'formfield type-text' },
- :descendant => {:tag => 'input', :attributes => {:id => 'profile_data_products_per_catalog_page'} }
- end
-
should 'show head and footer for admin' do
login_as('default_user')
get :index, :profile => profile.identifier
diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb
index c8ad201..3eddad2 100644
--- a/test/functional/search_controller_test.rb
+++ b/test/functional/search_controller_test.rb
@@ -1,6 +1,4 @@
-# encoding: UTF-8
-require_relative "../test_helper"
-require 'search_controller'
+require_relative '../test_helper'
class SearchControllerTest < ActionController::TestCase
@@ -22,8 +20,6 @@ class SearchControllerTest < ActionController::TestCase
domain.google_maps_key = 'ENVIRONMENT_KEY'
domain.save!
- @product_category = fast_create(ProductCategory)
-
# By pass user validation on person creation
user = mock()
user.stubs(:id).returns(1)
@@ -140,67 +136,6 @@ class SearchControllerTest < ActionController::TestCase
assert_equivalent [c2, c1], assigns(:searches)[:communities][:results]
end
- should 'search for products' do
- ent = create_profile_with_optional_category(Enterprise, 'teste')
- prod = ent.products.create!(:name => 'a beautiful product', :product_category => @product_category)
- get :products, :query => 'beautiful'
- assert_includes assigns(:searches)[:products][:results], prod
- end
-
- should 'include extra content supplied by plugins on product asset' do
- class Plugin1 < Noosfero::Plugin
- def asset_product_extras(product)
- proc {"This is Plugin1 speaking! ".html_safe}
- end
- end
-
- class Plugin2 < Noosfero::Plugin
- def asset_product_extras(product)
- proc {"This is Plugin2 speaking! ".html_safe}
- end
- end
- Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin2.to_s])
-
- enterprise = fast_create(Enterprise)
- prod_cat = fast_create(ProductCategory)
- product = fast_create(Product, {:profile_id => enterprise.id, :name => "produto1", :product_category_id => prod_cat.id}, :search => true)
-
- e = Environment.default
- e.enable_plugin(Plugin1.name)
- e.enable_plugin(Plugin2.name)
-
- get :products, :query => 'produto1'
-
- assert_tag :tag => 'span', :content => 'This is Plugin1 speaking!', :attributes => {:id => 'plugin1'}
- assert_tag :tag => 'span', :content => 'This is Plugin2 speaking!', :attributes => {:id => 'plugin2'}
- end
-
- should 'include extra properties of the product supplied by plugins' do
- class Plugin1 < Noosfero::Plugin
- def asset_product_properties(product)
- return { :name => _('Property1'), :content => proc { link_to(product.name, '/plugin1') } }
- end
- end
- class Plugin2 < Noosfero::Plugin
- def asset_product_properties(product)
- return { :name => _('Property2'), :content => proc { link_to(product.name, '/plugin2') } }
- end
- end
- Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin2.to_s])
- enterprise = fast_create(Enterprise)
- prod_cat = fast_create(ProductCategory)
- product = fast_create(Product, {:profile_id => enterprise.id, :name => "produto1", :product_category_id => prod_cat.id}, :search => true)
-
- environment = Environment.default
- environment.enable_plugin(Plugin1.name)
- environment.enable_plugin(Plugin2.name)
-
- get :products, :query => "produto1"
-
- assert_tag :tag => 'div', :content => /Property1/, :child => {:tag => 'a', :attributes => {:href => '/plugin1'}, :content => product.name}
- assert_tag :tag => 'div', :content => /Property2/, :child => {:tag => 'a', :attributes => {:href => '/plugin2'}, :content => product.name}
- end
-
should 'paginate enterprise listing' do
@controller.expects(:limit).returns(1).at_least_once
ent1 = create_profile_with_optional_category(Enterprise, 'teste 1')
@@ -253,29 +188,8 @@ class SearchControllerTest < ActionController::TestCase
assert_includes assigns(:searches)[:people][:results], p
end
- should 'render specific action when only one asset is enabled' do
- environment = Environment.default
- # article is not disabled
- [:enterprises, :people, :communities, :products, :events].select do |key, name|
- environment.enable('disable_asset_' + key.to_s)
- end
- environment.save!
- @controller.stubs(:environment).returns(environment)
-
- get :index, :query => 'something'
-
- assert assigns(:searches).has_key?(:articles)
- refute assigns(:searches).has_key?(:enterprises)
- refute assigns(:searches).has_key?(:people)
- refute assigns(:searches).has_key?(:communities)
- refute assigns(:searches).has_key?(:products)
- refute assigns(:searches).has_key?(:events)
- end
-
should 'search all enabled assets in general search' do
ent1 = create_profile_with_optional_category(Enterprise, 'test enterprise')
- prod_cat = create(ProductCategory, :name => 'pctest', :environment => Environment.default)
- prod = create(Product,:name => 'test product', :product_category => prod_cat, :enterprise => ent1)
art = create(Article, :name => 'test article', :profile_id => fast_create(Person).id)
per = create(Person, :name => 'test person', :identifier => 'test-person', :user_id => fast_create(User).id)
com = create(Community, :name => 'test community')
@@ -283,7 +197,7 @@ class SearchControllerTest < ActionController::TestCase
get :index, :query => 'test'
- [:articles, :enterprises, :people, :communities, :products, :events].select do |key, name|
+ [:articles, :enterprises, :people, :communities, :events].select do |key, name|
!assigns(:environment).enabled?('disable_asset_' + key.to_s)
end.each do |asset|
refute assigns(:searches)[asset][:results].empty?
@@ -379,37 +293,13 @@ class SearchControllerTest < ActionController::TestCase
assert_equal 20, assigns(:events).size
end
- %w[ people enterprises articles events communities products ].each do |asset|
+ %w[ people enterprises articles events communities ].each do |asset|
should "render asset-specific template when searching for #{asset}" do
get "#{asset}"
assert_template asset
end
end
- should 'display only within a product category when specified' do
- prod_cat = create(ProductCategory, :name => 'prod cat test', :environment => Environment.default)
- ent = create_profile_with_optional_category(Enterprise, 'test ent')
-
- p = create(Product, :product_category => prod_cat, :name => 'prod test 1', :enterprise => ent)
-
- get :products, :product_category => prod_cat.id
-
- assert_includes assigns(:searches)[:products][:results], p
- end
-
- should 'display properly in conjuntion with a category' do
- cat = create(Category, :name => 'cat', :environment => Environment.default)
- prod_cat1 = create(ProductCategory, :name => 'prod cat test 1', :environment => Environment.default)
- prod_cat2 = create(ProductCategory, :name => 'prod cat test 2', :environment => Environment.default, :parent => prod_cat1)
- ent = create_profile_with_optional_category(Enterprise, 'test ent', cat)
-
- product = create(Product, :product_category => prod_cat2, :name => 'prod test 1', :profile_id => ent.id)
-
- get :products, :category_path => cat.path.split('/'), :product_category => prod_cat1.id
-
- assert_includes assigns(:searches)[:products][:results], product
- end
-
should 'provide calendar for events' do
get :events
assert_equal 0, assigns(:calendar).size % 7
@@ -452,20 +342,6 @@ class SearchControllerTest < ActionController::TestCase
assert_equal 20, assigns(:searches)[:enterprises][:results].total_entries
end
- should 'find products when enterprises has own hostname' do
- ent = create_profile_with_optional_category(Enterprise, 'teste')
- ent.domains << Domain.new(:name => 'testent.com'); ent.save!
- prod = ent.products.create!(:name => 'a beautiful product', :product_category => @product_category)
- get 'products', :query => 'beautiful'
- assert_includes assigns(:searches)[:products][:results], prod
- end
-
- should 'add script tag for google maps if searching products' do
- get 'products', :query => 'product', :display => 'map'
-
- assert_tag :tag => 'script', :attributes => { :src => 'http://maps.google.com/maps/api/js?sensor=true'}
- end
-
should 'add script tag for google maps if searching enterprises' do
ent = create_profile_with_optional_category(Enterprise, 'teste')
get 'enterprises', :query => 'enterprise', :display => 'map'
@@ -572,8 +448,6 @@ class SearchControllerTest < ActionController::TestCase
assert_redirected_to :controller => :search, :action => :people
get :assets, :asset => 'communities'
assert_redirected_to :controller => :search, :action => :communities
- get :assets, :asset => 'products'
- assert_redirected_to :controller => :search, :action => :products
get :assets, :asset => 'enterprises'
assert_redirected_to :controller => :search, :action => :enterprises
get :assets, :asset => 'events'
@@ -633,20 +507,6 @@ class SearchControllerTest < ActionController::TestCase
assert_equal [art2, art1, art3], assigns(:searches)[:articles][:results]
end
- should 'add highlighted CSS class around a highlighted product' do
- enterprise = fast_create(Enterprise)
- product = create(Product, :name => 'Enter Sandman', :profile_id => enterprise.id, :product_category_id => @product_category.id, :highlighted => true)
- get :products
- assert_tag :tag => 'li', :attributes => { :class => 'search-product-item highlighted' }, :content => /Enter Sandman/
- end
-
- should 'do not add highlighted CSS class around an ordinary product' do
- enterprise = fast_create(Enterprise)
- product = create(Product, :name => 'Holier Than Thou', :profile_id => enterprise.id, :product_category_id => @product_category.id, :highlighted => false)
- get :products
- assert_no_tag :tag => 'li', :attributes => { :class => 'search-product-item highlighted' }, :content => /Holier Than Thou/
- end
-
should 'get search suggestions on json' do
st1 = 'universe A'
st2 = 'universe B'
diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb
index a84eceb..9a2cd19 100644
--- a/test/integration/routing_test.rb
+++ b/test/integration/routing_test.rb
@@ -158,10 +158,6 @@ class RoutingTest < ActionDispatch::IntegrationTest
assert_routing('/ze~withtilde', :controller => 'content_viewer', :action => 'view_page', :profile => 'ze~withtilde')
end
- def test_catalog_routing
- assert_routing('/catalog/colivre', :controller => 'catalog', :action => 'index', :profile => 'colivre')
- end
-
def test_hosted_domain_routing
user = create_user('testuser').person
domain = Domain.new(:name => 'example.com').tap { |d| d.owner = user; d.save! }
diff --git a/test/support/factories.rb b/test/support/factories.rb
index bd35f9d..3c853c4 100644
--- a/test/support/factories.rb
+++ b/test/support/factories.rb
@@ -52,9 +52,7 @@ module Noosfero::Factory
end
def defaults_for(name)
- send('defaults_for_' + name.to_s.underscore)
- rescue
- {}
+ send "defaults_for_#{name.to_s.underscore.tr '/', '_'}" rescue {}
end
def self.num_seq
@@ -316,7 +314,6 @@ module Noosfero::Factory
end
alias :defaults_for_region :defaults_for_category
- alias :defaults_for_product_category :defaults_for_category
###############################################
# Box
@@ -348,22 +345,6 @@ module Noosfero::Factory
alias :defaults_for_email_activation :defaults_for_task
###############################################
- # Product
- ###############################################
-
- def defaults_for_product
- { :name => 'Product ' + factory_num_seq.to_s }
- end
-
- ###############################################
- # Input
- ###############################################
-
- def defaults_for_input
- { }
- end
-
- ###############################################
# Contact
###############################################
@@ -372,22 +353,6 @@ module Noosfero::Factory
end
###############################################
- # Qualifier
- ###############################################
-
- def defaults_for_qualifier
- { :name => 'Qualifier ' + factory_num_seq.to_s, :environment_id => 1 }
- end
-
- ###############################################
- # Certifier
- ###############################################
-
- def defaults_for_certifier
- defaults_for_qualifier.merge({ :name => 'Certifier ' + factory_num_seq.to_s })
- end
-
- ###############################################
# Scrap
###############################################
@@ -464,22 +429,6 @@ module Noosfero::Factory
end
###############################################
- # Unit
- ###############################################
-
- def defaults_for_unit
- { :singular => 'Litre', :plural => 'Litres', :environment_id => 1 }
- end
-
- ###############################################
- # Production Cost
- ###############################################
-
- def defaults_for_production_cost
- { :name => 'Production cost ' + factory_num_seq.to_s }
- end
-
- ###############################################
# National Region
###############################################
diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb
index 5e924a4..312aa88 100644
--- a/test/unit/article_test.rb
+++ b/test/unit/article_test.rb
@@ -459,10 +459,6 @@ class ArticleTest < ActiveSupport::TestCase
assert_includes categories_including_virtual, c3
end
- should 'not accept Product category as category' do
- refute Article.new.accept_category?(ProductCategory.new)
- end
-
should 'accept published attribute' do
assert_respond_to Article.new, :published
assert_respond_to Article.new, :published=
diff --git a/test/unit/box_test.rb b/test/unit/box_test.rb
index 5e1e701..2bcd071 100644
--- a/test/unit/box_test.rb
+++ b/test/unit/box_test.rb
@@ -44,7 +44,6 @@ class BoxTest < ActiveSupport::TestCase
assert blocks.include?('.profile-image-block')
assert blocks.include?('.raw-html-block')
assert blocks.include?('.recent-documents-block')
- assert blocks.include?('.sellers-search-block')
assert blocks.include?('.tags-block')
end
@@ -63,20 +62,17 @@ class BoxTest < ActiveSupport::TestCase
assert blocks.include?('.enterprises-block')
assert blocks.include?('.fans-block')
assert blocks.include?('.favorite-enterprises-block')
- assert blocks.include?('.featured-products-block')
assert blocks.include?('.feed-reader-block')
assert blocks.include?('.highlights-block')
assert blocks.include?('.link-list-block')
assert blocks.include?('.location-block')
assert blocks.include?('.login-block')
assert blocks.include?('.my-network-block')
- assert blocks.include?('.products-block')
assert blocks.include?('.profile-image-block')
assert blocks.include?('.profile-info-block')
assert blocks.include?('.profile-search-block')
assert blocks.include?('.raw-html-block')
assert blocks.include?('.recent-documents-block')
- assert blocks.include?('.sellers-search-block')
assert blocks.include?('.slideshow-block')
assert blocks.include?('.tags-block')
end
diff --git a/test/unit/catalog_helper_test.rb b/test/unit/catalog_helper_test.rb
deleted file mode 100644
index 65b52c2..0000000
--- a/test/unit/catalog_helper_test.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative "../test_helper"
-
-class CatalogHelperTest < ActiveSupport::TestCase
-
- include CatalogHelper
- include ActionView::Helpers::TextHelper
- include ActionView::Helpers::UrlHelper
- include ActionView::Helpers::TagHelper
- include ::Rails::Dom::Testing::Assertions::SelectorAssertions
-
- def url_for(opts)
- #{:controller => 'catalog', :action => 'index', :level => category.id}
- "#{opts[:controller]}-#{opts[:action]}-level=#{opts[:level]}"
- end
-
- def new_productcategory(parent, name)
- cat = ProductCategory.new(
- :name => name, :environment => Environment.default, :parent => parent
- )
- cat if cat.save
- end
-
- def setup
- @enterprise = Enterprise.create! :name => 'Test Enterprise',
- :identifier => 'testenterprise',
- :environment => Environment.default
- @profile = @enterprise
- @block = @enterprise.blocks.select{|b| b.class == ProductCategoriesBlock }[0]
- @products = new_productcategory nil, 'Products'
- @food = new_productcategory @products, 'Food'
- @vegetables = new_productcategory @food, 'Vegetables'
- @beans = new_productcategory @vegetables, 'Beans'
- @rice = new_productcategory @vegetables, 'Rice'
- @mineral = new_productcategory @products, 'Mineral'
- @iron = new_productcategory @mineral, 'Iron'
- @gold = new_productcategory @mineral, 'Gold'
- end
- attr_accessor :profile
-
- should 'list product category sub-list' do
- @enterprise.products.create!(:name => 'Gold Ring', :product_category => @gold)
- @enterprise.products.create!(:name => 'Uncle Jon Beans', :product_category => @beans)
- @enterprise.products.create!(:name => 'Red Rice', :product_category => @rice)
-
- html = category_with_sub_list @products
-
- doc = Nokogiri::HTML "#{html}"
- assert_select doc, 'div' do |divs|
- assert_select divs[0], "a[href=catalog-index-level=#{@products.id}]"
- assert_select divs[0], '.count', {:text=>'3'}
- assert_select divs[1], "a[href=catalog-index-level=#{@food.id}]"
- assert_select divs[1], '.count', {:text=>'2'}
- assert_select divs[2], "a[href=catalog-index-level=#{@mineral.id}]"
- assert_select divs[2], '.count', {:text=>'1'}
- end
- end
-
-end
diff --git a/test/unit/categories_helper_test.rb b/test/unit/categories_helper_test.rb
index 922ce22..660a17f 100644
--- a/test/unit/categories_helper_test.rb
+++ b/test/unit/categories_helper_test.rb
@@ -12,7 +12,7 @@ class CategoriesHelperTest < ActiveSupport::TestCase
should 'generate list of category types for selection' do
expects(:params).returns({'fieldname' => 'fieldvalue'})
- expects(:options_for_select).with([['General Category', 'Category'],[ 'Product Category', 'ProductCategory'],[ 'Region', 'Region' ]], 'fieldvalue').returns('OPTIONS')
+ expects(:options_for_select).with([['General Category', 'Category'], [ 'Region', 'Region' ]], 'fieldvalue').returns('OPTIONS')
expects(:select_tag).with('type', 'OPTIONS').returns('TAG')
expects(:labelled_form_field).with(anything, 'TAG').returns('RESULT')
diff --git a/test/unit/category_test.rb b/test/unit/category_test.rb
index e43f81c..8fd8f1e 100644
--- a/test/unit/category_test.rb
+++ b/test/unit/category_test.rb
@@ -4,7 +4,7 @@ require_relative "../test_helper"
class CategoryTest < ActiveSupport::TestCase
def setup
- @env = fast_create(Environment)
+ @env = Environment.default
end
def test_mandatory_field_name
@@ -16,7 +16,7 @@ class CategoryTest < ActiveSupport::TestCase
def test_mandatory_field_name
c = Category.new
- c.name = 'product category for testing'
+ c.name = 'category for testing'
refute c.valid?
assert c.errors[:environment_id.to_s].present?
end
@@ -184,7 +184,6 @@ class CategoryTest < ActiveSupport::TestCase
assert c.recent_people.respond_to? 'total_entries'
assert c.recent_enterprises.respond_to? 'total_entries'
assert c.recent_communities.respond_to? 'total_entries'
- assert c.recent_products.respond_to? 'total_entries'
assert c.recent_articles.respond_to? 'total_entries'
assert c.recent_comments.respond_to? 'total_entries'
assert c.most_commented_articles.respond_to? 'total_entries'
@@ -223,18 +222,6 @@ class CategoryTest < ActiveSupport::TestCase
assert_equal [c2, c1], c.recent_communities
end
- should 'list recent products' do
- product_category = fast_create(ProductCategory, :name => 'Products', :environment_id => Environment.default.id)
- c = @env.categories.build(:name => 'my category'); c.save!
- ent1 = fast_create(Enterprise, :identifier => 'enterprise_1', :name => 'Enterprise one')
- ent1.add_category c
- ent2 = fast_create(Enterprise, :identifier => 'enterprise_2', :name => 'Enterprise one')
- ent2.add_category c
- prod1 = ent1.products.create!(:name => 'test_prod1', :product_category => product_category)
- prod2 = ent2.products.create!(:name => 'test_prod2', :product_category => product_category)
- assert_equal [prod2, prod1], c.recent_products
- end
-
should 'list recent articles' do
c = @env.categories.build(:name => 'my category'); c.save!
person = create_user('testuser').person
@@ -326,19 +313,6 @@ class CategoryTest < ActiveSupport::TestCase
assert_equivalent [c1, c2], c.communities
end
- should 'have products through enterprises' do
- product_category = fast_create(ProductCategory, :name => 'Products', :environment_id => Environment.default.id)
- c = @env.categories.build(:name => 'my category'); c.save!
- ent1 = fast_create(Enterprise, :identifier => 'enterprise_1', :name => 'Enterprise one')
- ent1.add_category c
- ent2 = fast_create(Enterprise, :identifier => 'enterprise_2', :name => 'Enterprise one')
- ent2.add_category c
- prod1 = ent1.products.create!(:name => 'test_prod1', :product_category => product_category)
- prod2 = ent2.products.create!(:name => 'test_prod2', :product_category => product_category)
- assert_includes c.products, prod1
- assert_includes c.products, prod2
- end
-
should 'not have person through communities' do
c = @env.categories.build(:name => 'my category'); c.save!
com = fast_create(Community, :identifier => 'community_1', :name => 'Community one')
@@ -401,28 +375,20 @@ class CategoryTest < ActiveSupport::TestCase
assert_equal 2, c.children.size
end
- should 'accept_products is true by default' do
- assert Category.new.accept_products?
- end
-
should 'get categories by type including nil' do
category = create(Category, :name => 'test category', :environment => Environment.default)
region = create(Region, :name => 'test region', :environment => Environment.default)
- product = create(ProductCategory, :name => 'test product', :environment => Environment.default)
- result = Category.from_types(['ProductCategory', '']).all
- assert_equal 2, result.size
- assert result.include?(product)
+ result = Category.from_types(['City', '']).all
+ assert_equal 1, result.size
assert result.include?(category)
end
should 'get categories by type and not nil' do
category = create(Category, :name => 'test category', :environment => Environment.default)
region = create(Region, :name => 'test region', :environment => Environment.default)
- product = create(ProductCategory, :name => 'test product', :environment => Environment.default)
- result = Category.from_types(['Region', 'ProductCategory']).all
- assert_equal 2, result.size
+ result = Category.from_types(['Region', 'City']).all
+ assert_equal 1, result.size
assert result.include?(region)
- assert result.include?(product)
end
should 'define a leaf to be displayed in menu' do
@@ -440,15 +406,15 @@ class CategoryTest < ActiveSupport::TestCase
end
should 'filter top_level categories by type' do
- toplevel_productcategory = fast_create(ProductCategory)
- leaf_productcategory = fast_create(ProductCategory, :parent_id => toplevel_productcategory.id)
+ toplevel_productcategory = fast_create(Region)
+ leaf_productcategory = fast_create(Region, :parent_id => toplevel_productcategory.id)
toplevel_category = fast_create(Category)
leaf_category = fast_create(Category, :parent_id => toplevel_category.id)
- assert_includes Category.top_level_for(Environment.default).from_types(['ProductCategory']), toplevel_productcategory
- assert_not_includes Category.top_level_for(Environment.default).from_types(['ProductCategory']), leaf_productcategory
- assert_not_includes Category.top_level_for(Environment.default).from_types(['ProductCategory']), toplevel_category
+ assert_includes Category.top_level_for(Environment.default).from_types(['Region']), toplevel_productcategory
+ assert_not_includes Category.top_level_for(Environment.default).from_types(['Region']), leaf_productcategory
+ assert_not_includes Category.top_level_for(Environment.default).from_types(['Region']), toplevel_category
end
should 'paginate upcoming events' do
diff --git a/test/unit/certifier_test.rb b/test/unit/certifier_test.rb
deleted file mode 100644
index 4f37639..0000000
--- a/test/unit/certifier_test.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# encoding: UTF-8
-require_relative "../test_helper"
-
-class CertifierTest < ActiveSupport::TestCase
-
- should 'have link' do
- certifier = Certifier.new
-
- assert_equal '', certifier.link
-
- certifier.link = 'http://noosfero.org'
- assert_equal 'http://noosfero.org', certifier.link
- end
-
- should 'environment is mandatory' do
- certifier = Certifier.new(:name => 'Certifier without environment')
- refute certifier.valid?
-
- certifier.environment = fast_create(Environment)
- assert certifier.valid?
- end
-
- should 'belongs to environment' do
- env_one = fast_create(Environment)
- certifier_from_env_one = env_one.certifiers.create(:name => 'Certifier from environment one')
-
- env_two = fast_create(Environment)
- certifier_from_env_two = env_two.certifiers.create(:name => 'Certifier from environment two')
-
- assert_includes env_one.certifiers, certifier_from_env_one
- assert_not_includes env_one.certifiers, certifier_from_env_two
- end
-
- should 'name is mandatory' do
- env_one = fast_create(Environment)
- certifier = env_one.certifiers.new
- refute certifier.valid?
-
- certifier.name = 'Certifier name'
- assert certifier.valid?
- end
-
- should 'sort by name' do
- last = fast_create(Certifier, :name => "Zumm")
- first = fast_create(Certifier, :name => "Atum")
- assert_equal [first, last], Certifier.all.sort
- end
-
- should 'sorting is not case sensitive' do
- first = fast_create(Certifier, :name => "Aaaa")
- second = fast_create(Certifier, :name => "abbb")
- last = fast_create(Certifier, :name => "Accc")
- assert_equal [first, second, last], Certifier.all.sort
- end
-
- should 'discard non-ascii char when sorting' do
- first = fast_create(Certifier, :name => "Áaaa")
- last = fast_create(Certifier, :name => "Aáab")
- assert_equal [first, last], Certifier.all.sort
- end
-
- should 'set qualifier as self-certified when destroyed' do
- pq = mock
- Certifier.any_instance.stubs(:product_qualifiers).returns([pq])
- pq.expects(:update!).with(:certifier => nil)
- cert = fast_create(Certifier)
- cert.destroy
- end
-
-end
diff --git a/test/unit/enterprise_homepage_helper_test.rb b/test/unit/enterprise_homepage_helper_test.rb
deleted file mode 100644
index a1fe70a..0000000
--- a/test/unit/enterprise_homepage_helper_test.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative "../test_helper"
-
-class EnterpriseHomepageHelperTest < ActiveSupport::TestCase
-
- include EnterpriseHomepageHelper
-
- def setup
- @profile = mock
- profile.stubs(:profile_image).returns('profileimage.png')
- self.stubs(:url_for).returns('link to profile')
- profile.stubs(:name).returns('Name of Profile')
- profile.stubs(:url).returns('')
- profile.stubs(:products).returns([Product.new(:name => 'product test')])
- profile.stubs(:identifier).returns('name-of-profile')
- profile.stubs(:region).returns(Region.new(:name => 'Brazil'))
- profile.stubs(:address).returns('Address of Profile')
- profile.stubs(:contact_email).returns('Email of Profile')
- profile.stubs(:contact_phone).returns('Phone of Profile')
- profile.stubs(:contact_person).returns('Profile Owner')
- profile.stubs(:location).returns('Profile Location');
- profile.stubs(:economic_activity).returns('Profile Economic Activity');
- end
- attr_reader :profile
-
- should 'display profile info' do
- result = display_profile_info(profile)
- assert_match /Profile Owner/, result
- assert_match /Email of Profile/, result
- assert_match /Phone of Profile/, result
- assert_match /Profile Location/, result
- assert_match /Address of Profile/, result
- assert_match /Profile Economic Activity/, result
- end
-
- should 'not display attribute if nil' do
- profile.stubs(:contact_person).returns(nil);
- result = display_profile_info(profile)
- assert_no_match /Profile Owner/, result
- end
-
- should 'not display attribute if blank' do
- profile.stubs(:contact_person).returns('');
- result = display_profile_info(profile)
- assert_no_match /Profile Owner/, result
- end
-
- should 'display distance' do
- profile.stubs(:distance).returns(100.345);
- result = display_profile_info(profile)
- assert_match /Distance:/, result
- assert_match /100.34/, result
- end
-
- should 'not display distance if nil' do
- profile.stubs(:distance).returns(nil);
- result = display_profile_info(profile)
- assert_no_match /Distance:/, result
- assert_no_match /100.34/, result
- end
-
- protected
- include NoosferoTestHelper
-
-end
diff --git a/test/unit/enterprise_homepage_test.rb b/test/unit/enterprise_homepage_test.rb
deleted file mode 100644
index 3494c19..0000000
--- a/test/unit/enterprise_homepage_test.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative "../test_helper"
-
-class EnterpriseHomepageTest < ActiveSupport::TestCase
-
- def setup
- @profile = create_user('testing').person
- @product_category = fast_create(ProductCategory, :name => 'Products')
- end
- attr_reader :profile
-
- should 'provide a proper short description' do
- assert_kind_of String, EnterpriseHomepage.short_description
- end
-
- should 'provide a proper description' do
- assert_kind_of String, EnterpriseHomepage.description
- end
-
- should 'return a valid body' do
- e = EnterpriseHomepage.new(:name => 'sample enterprise homepage')
- assert_not_nil e.to_html
- end
-
- should 'can display hits' do
- a = EnterpriseHomepage.new(:name => 'Test article')
- assert_equal false, a.can_display_hits?
- end
-
- should 'have can_display_media_panel with default true' do
- a = EnterpriseHomepage.new
- assert a.can_display_media_panel?
- end
-
-end
diff --git a/test/unit/enterprise_test.rb b/test/unit/enterprise_test.rb
index 000b329..6e2b7ad 100644
--- a/test/unit/enterprise_test.rb
+++ b/test/unit/enterprise_test.rb
@@ -2,13 +2,8 @@
require_relative "../test_helper"
class EnterpriseTest < ActiveSupport::TestCase
- fixtures :profiles, :environments, :users
- def setup
- super
- Environment.default.enable('products_for_enterprises')
- @product_category = fast_create(ProductCategory, :name => 'Products')
- end
+ fixtures :profiles, :environments, :users
def test_identifier_validation
p = Enterprise.new
@@ -61,16 +56,6 @@ class EnterpriseTest < ActiveSupport::TestCase
assert_includes Enterprise.find(e.id).fans, p
end
- should 'remove products when removing enterprise' do
- e = fast_create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise')
- create(Product, :enterprise => e, :name => 'One product', :product_category => @product_category)
- create(Product, :enterprise => e, :name => 'Another product', :product_category => @product_category)
-
- assert_difference 'Product.count', -2 do
- e.destroy
- end
- end
-
should 'create a default set of articles' do
blog = build(Blog)
Enterprise.any_instance.expects(:default_set_of_articles).returns([blog])
@@ -237,21 +222,6 @@ class EnterpriseTest < ActiveSupport::TestCase
assert enterprise.enable(person)
end
- should 'list product categories' do
- subcategory = fast_create(ProductCategory, :name => 'Products subcategory', :parent_id => @product_category.id)
- ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent')
- p = create(Product, :name => 'test prod', :product_category => subcategory, :enterprise => ent)
-
- assert_equivalent [subcategory], ent.product_categories
- end
-
- should 'not create a products block for enterprise if environment do not let' do
- env = Environment.default
- env.disable('products_for_enterprises')
- ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent')
- assert_not_includes ent.blocks.map(&:class), ProductsBlock
- end
-
should 'have a enterprise template' do
template = fast_create(Enterprise, :is_template => true)
p = fast_create(Enterprise, :name => 'test_com', :identifier => 'test_com', :template_id => template.id)
@@ -403,33 +373,6 @@ class EnterpriseTest < ActiveSupport::TestCase
assert_equal 4, ent.boxes.size
end
- should 'collect the highlighted products with image' do
- env = Environment.default
- e1 = fast_create(Enterprise)
- p1 = create(Product, :name => 'test_prod1', :product_category_id => @product_category.id, :enterprise => e1)
- products = []
- 3.times {|n|
- products.push(create(Product, :name => "product #{n}", :profile_id => e1.id,
- :highlighted => true, :product_category_id => @product_category.id,
- :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
- ))
- }
- create(Product, :name => "product 4", :profile_id => e1.id, :product_category_id => @product_category.id, :highlighted => true)
- create(Product, :name => "product 5", :profile_id => e1.id, :product_category_id => @product_category.id, :image_builder => {
- :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
- })
- assert_equal products, e1.highlighted_products_with_image
- end
-
- should 'have many inputs through products' do
- enterprise = fast_create(Enterprise)
- product = fast_create(Product, :profile_id => enterprise.id, :product_category_id => @product_category.id)
- product.inputs << build(Input, :product_category => @product_category)
- product.inputs << build(Input, :product_category => @product_category)
-
- assert_equal product.inputs.sort, enterprise.inputs.sort
- end
-
should "the followed_by? be true only to members" do
e = fast_create(Enterprise)
e.stubs(:closed?).returns(false)
@@ -455,11 +398,6 @@ class EnterpriseTest < ActiveSupport::TestCase
assert_equal false, enterprise.receives_scrap_notification?
end
- should 'have production cost' do
- e = fast_create(Enterprise)
- assert_respond_to e, :production_costs
- end
-
should 'return scraps as activities' do
person = fast_create(Person)
enterprise = fast_create(Enterprise)
@@ -492,13 +430,6 @@ class EnterpriseTest < ActiveSupport::TestCase
assert_not_includes enterprise.activities.map(&:activity), article.activity
end
- should 'provide URL to catalog area' do
- environment = create_environment('mycolivre.net')
- enterprise = build(Enterprise, :identifier => 'testprofile', :environment_id => create_environment('mycolivre.net').id)
-
- assert_equal({:profile => enterprise.identifier, :controller => 'catalog'}, enterprise.catalog_url)
- end
-
should 'check if a community admin user is really a community admin' do
c = fast_create(Enterprise, :name => 'my test profile', :identifier => 'mytestprofile')
admin = create_user('adminuser').person
diff --git a/test/unit/environment_test.rb b/test/unit/environment_test.rb
index 46faee7..c4dc1b8 100644
--- a/test/unit/environment_test.rb
+++ b/test/unit/environment_test.rb
@@ -138,22 +138,6 @@ class EnvironmentTest < ActiveSupport::TestCase
assert cats.include?(subcat)
end
- def test_should_list_all_product_categories
- env = fast_create(Environment)
- create(Category, :name => 'first category', :environment_id => env.id)
- cat = create(Category, :name => 'second category', :environment_id => env.id)
- create(Category, :name => 'child category', :environment_id => env.id, :parent_id => cat.id)
- cat1 = create(ProductCategory, :name => 'first product category', :environment_id => env.id)
- cat2 = create(ProductCategory, :name => 'second product category', :environment_id => env.id)
- subcat = create(ProductCategory, :name => 'child product category', :environment_id => env.id, :parent_id => cat2.id)
-
- cats = env.product_categories
- assert_equal 3, cats.size
- assert cats.include?(cat1)
- assert cats.include?(cat2)
- assert cats.include?(subcat)
- end
-
should 'list displayable categories' do
env = fast_create(Environment)
cat1 = create(Category, :environment => env, :name => 'category one', :display_color => 'ffa500')
@@ -389,34 +373,6 @@ class EnvironmentTest < ActiveSupport::TestCase
assert_not_includes Environment.default.admins, user
end
- should 'have products through enterprises' do
- product_category = fast_create(ProductCategory, :name => 'Products', :environment_id => Environment.default.id)
- env = Environment.default
- e1 = fast_create(Enterprise)
- p1 = e1.products.create!(:name => 'test_prod1', :product_category => product_category)
-
- assert_includes env.products, p1
- end
-
- should 'collect the highlighted products with image through enterprises' do
- env = Environment.default
- e1 = fast_create(Enterprise)
- category = fast_create(ProductCategory)
- p1 = create(Product, :enterprise => e1, :name => 'test_prod1', :product_category_id => category.id)
- products = []
- 3.times {|n|
- products.push(create(Product, :name => "product #{n}", :profile_id => e1.id,
- :product_category_id => category.id, :highlighted => true,
- :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
- ))
- }
- create(Product, :name => "product 4", :profile_id => e1.id, :product_category_id => category.id, :highlighted => true)
- create(Product, :name => "product 5", :profile_id => e1.id, :product_category_id => category.id, :image_builder => {
- :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
- })
- assert_equal products, env.highlighted_products_with_image
- end
-
should 'not have person through communities' do
env = Environment.default
com = fast_create(Community)
@@ -1319,14 +1275,6 @@ class EnvironmentTest < ActiveSupport::TestCase
assert_not_includes env.enabled_features.keys, 'feature3'
end
- should 'has a list of units ordered by position' do
- litre = create(Unit, :singular => 'Litre', :plural => 'Litres', :environment => Environment.default)
- meter = create(Unit, :singular => 'Meter', :plural => 'Meters', :environment => Environment.default)
- kilo = create(Unit, :singular => 'Kilo', :plural => 'Kilo', :environment => Environment.default)
- litre.move_to_bottom
- assert_equal ["Meter", "Kilo", "Litre"], Environment.default.units.map(&:singular)
- end
-
should 'not include port in default hostname' do
env = Environment.new
Noosfero.stubs(:url_options).returns({ :port => 9999 })
@@ -1450,10 +1398,6 @@ class EnvironmentTest < ActiveSupport::TestCase
end
end
- should 'have production costs' do
- assert_respond_to Environment.default, :production_costs
- end
-
should 'be able to have many licenses' do
environment = Environment.default
another_environment = fast_create(Environment)
diff --git a/test/unit/featured_products_block_test.rb b/test/unit/featured_products_block_test.rb
deleted file mode 100644
index 015cd0d..0000000
--- a/test/unit/featured_products_block_test.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-require_relative "../test_helper"
-require 'boxes_helper'
-
-class FeaturedProductsBlockTest < ActiveSupport::TestCase
- include BoxesHelper
-
- def setup
- @profile = fast_create(Profile)
- @environment = Environment.default
- @environment.boxes << Box.new
- end
- attr_reader :profile
-
- should 'refer to products' do
- profile = fast_create(Enterprise)
- products = []
- category = fast_create(ProductCategory)
- 3.times {|n| products.push(create(Product, :name => "product #{n}", :profile_id => profile.id, :product_category_id => category.id)) }
- featured_products_block = create(FeaturedProductsBlock, :product_ids => products.map(&:id))
- assert_equal products, featured_products_block.products
- end
-
- should "have method products_for_selection" do
- block = FeaturedProductsBlock.new
- assert_respond_to block, 'products_for_selection'
- end
-
- should " the defaul product_ids be an empty array" do
- block = FeaturedProductsBlock.new
- assert_equal [], block.product_ids
- end
-
- should " the defaul groups_of be 3" do
- block = FeaturedProductsBlock.new
- assert_equal 3, block.groups_of
- end
-
- should 'default interval between transitions is 1000 miliseconds' do
- block = FeaturedProductsBlock.new
- assert_equal 1000, block.speed
- end
-
- should "reflect by default" do
- block = FeaturedProductsBlock.new
- assert_equal true, block.reflect
- end
-
- should 'describe itself' do
- assert_not_equal Block.description, FeaturedProductsBlock.description
- end
-
- should "the groups_of variabe be a integer" do
- block = FeaturedProductsBlock.new
- assert_kind_of Integer, block.groups_of
- block.groups_of = 2
- block.save
- block.reload
- assert_kind_of Integer, block.groups_of
- block.groups_of = '2'
- block.save
- block.reload
- assert_kind_of Integer, block.groups_of
- end
-
- should "an environment block collect product automatically" do
- block = build(FeaturedProductsBlock, )
- block.product_ids = []
- enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
- category = fast_create(ProductCategory)
- 3.times {|n|
- create(Product, :name => "product #{n}", :profile_id => enterprise.id,
- :highlighted => true, :product_category_id => category.id,
- :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
- )
- }
- @environment.boxes.first.blocks<< block
-
- assert_not_equal [], block.product_ids
- end
-
- should "an environment block collect just product with image automatically" do
- block = build(FeaturedProductsBlock, )
- block.product_ids = []
- enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
- category = fast_create(ProductCategory)
- 3.times {|n|
- create(Product, :name => "product #{n}", :profile_id => enterprise.id, :highlighted => true, :product_category_id => category.id)
- }
- @environment.boxes.first.blocks<< block
-
- assert_equal [], block.product_ids
- end
-
- should "an environment block collect just highlighted product automatically" do
- block = build(FeaturedProductsBlock, )
- block.product_ids = []
- enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
- category = fast_create(ProductCategory)
- 3.times {|n|
- create(Product, :name => "product #{n}", :profile_id => enterprise.id, :product_category_id => category.id, :image_builder => {
- :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
- })
- }
- @environment.boxes.first.blocks<< block
-
- assert_equal [], block.product_ids
- end
-
- should 'display feature products block' do
- block = FeaturedProductsBlock.new
-
- self.expects(:render).with(template: 'blocks/featured_products', locals: {block: block})
- render_block_content(block)
- end
-
- should "return just highlighted products with image for selection" do
- block = build(FeaturedProductsBlock, )
- block.product_ids = []
- enterprise = create(Enterprise, :name => "My enterprise", :identifier => 'myenterprise', :environment => @environment)
- category = fast_create(ProductCategory)
- products = []
- 3.times {|n|
- products.push(create(Product, :name => "product #{n}", :profile_id => enterprise.id,
- :highlighted => true, :product_category_id => category.id,
- :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png') }
- ))
- }
- create(Product, :name => "product 4", :profile_id => enterprise.id, :product_category_id => category.id, :highlighted => true)
- create(Product, :name => "product 5", :profile_id => enterprise.id, :product_category_id => category.id, :image_builder => {
- :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')
- })
- @environment.boxes.first.blocks<< block
-
- products_for_selection = block.products_for_selection
-
- products.each do |product|
- assert_includes products_for_selection, product
- end
- end
-
-end
diff --git a/test/unit/input_test.rb b/test/unit/input_test.rb
deleted file mode 100644
index 48f0591..0000000
--- a/test/unit/input_test.rb
+++ /dev/null
@@ -1,194 +0,0 @@
-require_relative "../test_helper"
-
-class InputTest < ActiveSupport::TestCase
-
- should 'require product_category' do
- product_category = fast_create(ProductCategory, :name => 'Products')
-
- input = Input.new
- input.valid?
- assert input.errors[:product_category.to_s].present?
-
- input.product_category = product_category
- input.valid?
- refute input.errors[:product_category.to_s].present?
- end
-
- should 'require product' do
- product_category = fast_create(ProductCategory, :name => 'Products')
- product = fast_create(Product, :name => 'Computer', :product_category_id => product_category.id)
-
- input = Input.new
- input.valid?
- assert input.errors[:product.to_s].present?
-
- input.product = product
- input.valid?
- refute input.errors[:product.to_s].present?
- end
-
- should 'store inputs ordered by position' do
- product_category = fast_create(ProductCategory)
- product = fast_create(Product, :product_category_id => product_category.id)
-
- first_input = create(Input, :product => product, :product_category => product_category)
- assert_equal 1, first_input.position
-
- second_input = create(Input, :product => product, :product_category => product_category)
- assert_equal 2, second_input.position
- end
-
- should 'move input to top of input list' do
- product_category = fast_create(ProductCategory)
- product = fast_create(Product, :product_category_id => product_category.id)
-
- first_input = create(Input, :product => product, :product_category => product_category)
- second_input = create(Input, :product => product, :product_category => product_category)
- last_input = create(Input, :product => product, :product_category => product_category)
-
- assert_equal [first_input, second_input, last_input], product.inputs(true)
-
- last_input.move_to_top
-
- assert_equal [last_input, first_input, second_input], product.inputs(true)
- end
-
- should 'use name of product category' do
- product_category = fast_create(ProductCategory)
- product = fast_create(Product, :product_category_id => product_category.id)
- input = fast_create(Input, :product_id => product.id, :product_category_id => product_category.id)
-
- assert_not_nil input.name
- assert_equal product_category.name, input.name
- end
-
- should 'dont have price details when price related fields was not filled' do
- input = Input.new
- refute input.has_price_details?
- end
-
- should 'has price details if price_per_unit filled' do
- input = build(Input, :price_per_unit => 10.0)
- assert input.has_price_details?
- end
-
- should 'has price details if amount_used filled' do
- input = build(Input, :amount_used => 10)
- assert input.has_price_details?
- end
-
- should 'not have price details if only unit is filled' do
- input = build(Input, :unit => Unit.new)
- refute input.has_price_details?
- end
-
- should 'accept price_per_unit 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|
- new_input = build(Input, :price_per_unit => input)
- assert_equal output, new_input.price_per_unit
- end
- end
-
- should 'accept amount_used in american\'s or brazilian\'s quantidade 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|
- new_input = build(Input, :amount_used => input)
- assert_equal output, new_input.amount_used
- end
- end
-
- should 'display amount used' do
- ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
- product_category = fast_create(ProductCategory, :name => 'Products')
- product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
-
- input = build(Input, :product => product)
- input.amount_used = 10.45
- assert_equal '10.45', input.formatted_amount
- end
-
- should 'display blank if amount_used is blank or nil or zero' do
- input = Input.new
- assert_equal '', input.formatted_amount
- input.amount_used = ''
- input.save
-
- assert_equal '', input.formatted_amount
- end
-
- should 'display only integer value if decimal value is 00' do
- ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
- product_category = fast_create(ProductCategory, :name => 'Products')
- product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
-
- input = build(Input, :product => product)
- input.amount_used = 10.00
- assert_equal '10', input.formatted_amount
- end
-
- should 'display formatted value' do
- ent = fast_create(Enterprise, :name => 'test ent 1', :identifier => 'test_ent1')
- product_category = fast_create(ProductCategory, :name => 'Products')
- product = fast_create(Product, :profile_id => ent.id, :product_category_id => product_category.id)
-
- input = build(Input, :product => product)
- input.price_per_unit = 1.45
- assert_equal '1.45', input.formatted_value(:price_per_unit)
-
- input.price_per_unit = 1.4
- assert_equal '1.40', input.formatted_value(:price_per_unit)
-
- input.price_per_unit = 1
- assert_equal '1.00', input.formatted_value(:price_per_unit)
- end
-
- should 'has relation with unit' do
- input = Input.new
- assert_kind_of Unit, input.build_unit
- end
-
- should 'calculate cost of input' do
- input = build(Input, :amount_used => 10, :price_per_unit => 2.00)
- assert_equal 20.00, input.cost
- end
-
- should 'cost 0 if amount not defined' do
- input = build(Input, :price_per_unit => 2.00)
- assert_equal 0.00, input.cost
- end
-
- should 'cost 0 if price_per_unit is not defined' do
- input = build(Input, :amount_used => 10)
- assert_equal 0.00, input.cost
- end
-
- should 'list inputs relevants to price' do
- product_category = fast_create(ProductCategory)
- product = fast_create(Product, :product_category_id => product_category.id)
-
- i1 = create(Input, :product => product, :product_category => product_category, :relevant_to_price => true)
-
- i2 = create(Input, :product => product, :product_category => product_category, :relevant_to_price => false)
-
- i1.save!
- i2.save!
- assert_includes Input.relevant_to_price, i1
- assert_not_includes Input.relevant_to_price, i2
- end
-
-end
diff --git a/test/unit/manage_products_helper_test.rb b/test/unit/manage_products_helper_test.rb
deleted file mode 100644
index bd0bd85..0000000
--- a/test/unit/manage_products_helper_test.rb
+++ /dev/null
@@ -1,190 +0,0 @@
-# encoding: UTF-8
-require_relative "../test_helper"
-
-class ManageProductsHelperTest < ActionView::TestCase
-
- include ManageProductsHelper
- include ContentViewerHelper
- include ArticleHelper
- include ActionView::Helpers::AssetTagHelper
- include ApplicationHelper
-
- def setup
- stubs(:show_date).returns('')
- @environment = Environment.default
- @profile = create_user('blog_helper_test').person
- end
-
- should 'display select for categories' do
- category_1 = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- fast_create(ProductCategory, :name => 'Category 2.1', :environment_id => @environment.id, :parent_id => category_1.id)
- fast_create(ProductCategory, :name => 'Category 2.2', :environment_id => @environment.id, :parent_id => category_1.id)
-
- assert_tag_in_string select_for_categories(category_1.children(true), 1), :tag => 'select', :attributes => {:id => 'category_id'}
- end
-
- include ActionView::Helpers::NumberHelper
- should 'format price to environment currency' do
- @environment.currency_unit = "R$"
- @environment.currency_separator = ","
- @environment.currency_delimiter = "."
- @environment.save
- assert_equal 'R$ 10,00', float_to_currency(10.0)
- end
-
- should 'not display link to edit product when user does not have permission' do
- user = mock
- user.expects(:has_permission?).with(anything, anything).returns(false)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
- assert_equal '', edit_product_link_to_remote(product, 'field', 'link to edit')
- end
-
- should 'display link to edit product when user has permission' do
- user = User.new(:email => 'display-link@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(true)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
-
- expects(:link_to_remote).with('link to edit', {:update => "product-name", :loading => "loading_for_button('#link-edit-product-name')", :url => {:controller => 'manage_products', :action => 'edit', :id => product.id, :field => 'name'}, :method => :get}, anything).returns('LINK')
-
- assert_equal 'LINK', edit_product_link_to_remote(product, 'name', 'link to edit')
- end
-
- should 'not display link to edit product category when user does not have permission' do
- user = User.new(:email => 'not-display-link@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(false)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
- assert_equal '', edit_link('link to edit category', { :action => 'edit_category', :id => product.id })
- end
-
- should 'display link to edit product category when user has permission' do
- user = User.new(:email => 'display-link@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(true)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
-
- expects(:link_to).with('link to edit category', { :action => 'edit_category', :id => product.id }, {} ).returns('LINK')
-
- assert_equal 'LINK', edit_link('link to edit category', { :action => 'edit_category', :id => product.id })
- end
-
- should 'not display ui_button to edit product when user does not have permission' do
- user = User.new(:email => 'not-display-uibutton@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(false)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
- assert_equal '', edit_ui_button(product, 'field', 'link to edit')
- end
-
- should 'display ui_button_to_remote to edit product when user has permission' do
- user = User.new(:email => 'display-uibuttontoremote@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(true)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
-
- expects(:ui_button_to_remote).with('link to edit', {:update => "product-info", :url => {:controller => 'manage_products', :action => 'edit', :id => product.id, :field => 'info'}, :complete => "jQuery('#edit-product-button-ui-info').hide()", :method => :get, :loading => "loading_for_button('#edit-product-remote-button-ui-info')", }, :id => 'edit-product-remote-button-ui-info').returns('LINK')
-
- assert_equal 'LINK', edit_product_ui_button_to_remote(product, 'info', 'link to edit')
- end
-
-
- should 'display ui_button to edit product when user has permission' do
- user = User.new(:email => 'display-uibutton@email.invalid.com')
- user.expects(:has_permission?).with(anything, anything).returns(true)
- @controller = mock
- @controller.expects(:user).returns(user).at_least_once
- @controller.expects(:profile).returns(mock)
- category = fast_create(ProductCategory, :name => 'Category 1', :environment_id => @environment.id)
- product = fast_create(Product, :product_category_id => category.id)
-
- expects(:ui_button).with('link to edit', { :action => 'add_input', :id => product.id }, {}).returns('LINK')
-
- assert_equal 'LINK', edit_ui_button('link to edit', {:action => 'add_input', :id => product.id})
- end
-
- should 'show unit on label of amount selection' do
- input = build(Input)
- input.expects(:product).returns(build(Product, :unit => Unit.new(:singular => 'Meter')))
- assert_equal 'Amount used by meter of this product or service', label_amount_used(input)
- end
-
- should 'not show unit on label of amount selection if product has no unit selected' do
- input = build(Input)
- input.expects(:product).returns(Product.new)
- assert_equal 'Amount used in this product or service', label_amount_used(input)
- end
-
- should 'sort qualifiers by name' do
- fast_create(Qualifier, :name => 'Organic')
- fast_create(Qualifier, :name => 'Non Organic')
- result = qualifiers_for_select
- assert_equal ["Select...", "Non Organic", "Organic"], result.map{|i| i[0]}
- end
-
- should 'sort certifiers by name' do
- qualifier = fast_create(Qualifier, :name => 'Organic')
- fbes = fast_create(Certifier, :name => 'FBES')
- colivre = fast_create(Certifier, :name => 'Colivre')
- create(QualifierCertifier, :qualifier => qualifier, :certifier => colivre)
- create(QualifierCertifier, :qualifier => qualifier, :certifier => fbes)
-
- result = certifiers_for_select(qualifier)
- assert_equal ["Self declared", "Colivre", "FBES"], result.map{|i| i[0]}
- end
-
- should 'list qualifiers and certifiers of a product' do
- product = fast_create(Product)
- qualifier = fast_create(Qualifier)
- certifier = fast_create(Certifier)
- create(ProductQualifier, :product => product, :qualifier => qualifier, :certifier => certifier)
- assert_match /✔ Qualifier \d+ certified by Certifier \d+/, display_qualifiers(product)
- end
-
- should 'product survive to a Qualifier deletation' do
- product = fast_create(Product)
- qualifier = fast_create(Qualifier)
- certifier = fast_create(Certifier)
- create(ProductQualifier, :product => product, :qualifier => qualifier, :certifier => certifier)
- qualifier.destroy
- assert_nothing_raised do
- assert_no_match /✔ Qualifier \d+ certified by Certifier \d+/, display_qualifiers(product)
- end
- end
-
- should 'delete product Qualifier self-declared when Certifier is deleted' do
- product = fast_create(Product)
- qualifier = fast_create(Qualifier)
- certifier = fast_create(Certifier)
- create(ProductQualifier, :product => product, :qualifier => qualifier, :certifier => certifier)
- certifier.destroy
- assert_nothing_raised do
- result = display_qualifiers(product)
- assert_match /✔ Qualifier \d+ \(Self declared\)/, result
- assert_no_match /certified by Certifier \d+/, result
- end
- end
-
- protected
- include NoosferoTestHelper
- include ActionView::Helpers::TextHelper
-end
diff --git a/test/unit/price_detail_test.rb b/test/unit/price_detail_test.rb
deleted file mode 100644
index fdefef8..0000000
--- a/test/unit/price_detail_test.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-require_relative "../test_helper"
-
-class PriceDetailTest < ActiveSupport::TestCase
-
- should 'have price 0 by default' do
- p = PriceDetail.new
-
- assert p.price.zero?
- end
-
- should 'return zero on price if it is blank' do
- p = PriceDetail.new(:price => '')
-
- assert p.price.zero?
- end
-
- should 'accept price 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|
- new_price_detail = PriceDetail.new(:price => input)
- assert_equal output, new_price_detail.price
- end
- end
-
- should 'belongs to a product' do
- p = PriceDetail.new
-
- assert_respond_to p, :product
- end
-
- should 'product be mandatory' do
- p = PriceDetail.new
- p.valid?
-
- assert p.errors[:product_id].any?
- end
-
- should 'have production cost' do
- product = fast_create(Product)
- cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment')
- detail = product.price_details.create(:production_cost_id => cost.id, :price => 10)
-
- assert_equal cost, PriceDetail.find(detail.id).production_cost
- end
-
- should 'production cost not be mandatory' do
- product = fast_create(Product)
- price = PriceDetail.new
- price.product = product
- price.valid?
- assert price.errors.empty?
- end
-
- should 'the production cost be unique on scope of product' do
- product = fast_create(Product)
- cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'environment')
-
- detail1 = product.price_details.create(:production_cost_id => cost.id, :price => 10)
- detail2 = product.price_details.build(:production_cost_id => cost.id, :price => 10)
-
- detail2.valid?
- assert detail2.errors[:production_cost_id].any?
- end
-
- should 'format values to float with 2 decimals' do
- enterprise = fast_create(Enterprise)
- product = fast_create(Product, :profile_id => enterprise.id)
- 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_equal "10.00", price_detail.formatted_value(:price)
- end
-
- should 'have the production cost name as name' do
- product = fast_create(Product)
- cost = fast_create(ProductionCost, :name => 'Energy',:owner_id => Environment.default.id, :owner_type => 'environment')
-
- detail = product.price_details.create(:production_cost_id => cost.id, :price => 10)
-
- assert_equal 'Energy', detail.name
- end
-
-
-end
diff --git a/test/unit/product_categories_block_test.rb b/test/unit/product_categories_block_test.rb
deleted file mode 100644
index 1680c22..0000000
--- a/test/unit/product_categories_block_test.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative "../test_helper"
-
-class ProductCategoriesBlockTest < ActiveSupport::TestCase
- should 'not be visible if products are disabled on the environment ' do
- enterprise = fast_create(Enterprise)
- box = fast_create(Box, :owner_id => enterprise.id, :owner_type => 'Profile')
- block = ProductCategoriesBlock.new
- block.box = box
-
- block.box.environment.enable('products_for_enterprises')
- assert block.visible?
-
- block.box.environment.disable('products_for_enterprises')
- refute block.visible?
- end
-
- should 'have display option to show only on catalog' do
- assert ProductCategoriesBlock::DISPLAY_OPTIONS.include?('catalog_only')
- end
-
- should 'set display to catalog_only by default' do
- assert_equal 'catalog_only', ProductCategoriesBlock.new.display
- end
-
- should 'display block only on catalog if display is set to catalog_only' do
- enterprise = fast_create(Enterprise)
- box = fast_create(Box, :owner_id => enterprise.id, :owner_type => 'Profile')
- block = ProductCategoriesBlock.new
- block.box = box
- block.box.environment.enable('products_for_enterprises')
-
- refute block.visible?(:params => {:controller => 'any_other'})
- assert block.visible?(:params => {:controller => 'catalog'})
- end
-end
diff --git a/test/unit/product_category_test.rb b/test/unit/product_category_test.rb
deleted file mode 100644
index 766f7bb..0000000
--- a/test/unit/product_category_test.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-require_relative "../test_helper"
-
-class ProductCategoryTest < ActiveSupport::TestCase
-
- def test_all_products
- c0 = Environment.default.product_categories.create!(:name => 'base_cat')
- assert_equivalent [], c0.all_products
-
- profile = fast_create(Enterprise)
- p0 = profile.products.create(:name => 'product1', :product_category => c0)
- c0.reload
- assert_equivalent [p0], c0.all_products
-
- c1 = Environment.default.product_categories.create!(:name => 'cat_1', :parent => c0)
- p1 = profile.products.create(:name => 'product2', :product_category => c1)
- c0.reload; c1.reload
- assert_equivalent [p0, p1], c0.all_products
- assert_equivalent [p1], c1.all_products
- end
-
- should 'return top level product categories for environment when no parent product category specified' do
- env1 = Environment.create!(:name => 'test env 1')
- env2 = Environment.create!(:name => 'test env 2')
-
- c1 = env1.product_categories.create!(:name => 'test cat 1')
- c2 = env2.product_categories.create!(:name => 'test cat 2')
-
- assert_equal [c1], ProductCategory.menu_categories(nil, env1)
- end
-
- should 'return children of parent category' do
- c1 = Environment.default.product_categories.create!(:name => 'test cat 1')
- c11 = Environment.default.product_categories.create!(:name => 'test cat 11', :parent => c1)
- c2 = Environment.default.product_categories.create!(:name => 'test cat 2')
-
- assert_equal [c11], ProductCategory.menu_categories(c1, nil)
- end
-
- should 'provide a scope based on the enterprise' do
- enterprise = fast_create(Enterprise)
- c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
- c2 = ProductCategory.create!(:name => 'test cat 2', :environment => Environment.default)
- c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
- p1 = Product.new(:name => 'product1', :product_category => c1)
- p1.profile = enterprise
- p1.save!
- p3 = Product.new(:name => 'product3', :product_category => c2)
- p3.profile = enterprise
- p3.save!
-
- scope = ProductCategory.by_enterprise(enterprise)
-
- assert_equivalent [c1,c2], scope
- end
-
- should 'provide a scope based on the enterprise returning distinct elements' do
- enterprise = fast_create(Enterprise)
- c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
- c2 = ProductCategory.create!(:name => 'test cat 2', :environment => Environment.default)
- c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
- p1 = Product.new(:name => 'product1', :product_category => c1)
- p1.profile = enterprise
- p1.save!
- p2 = Product.new(:name => 'product2', :product_category => c1)
- p2.profile = enterprise
- p2.save!
- p3 = Product.new(:name => 'product3', :product_category => c2)
- p3.profile = enterprise
- p3.save!
-
- scope = ProductCategory.by_enterprise(enterprise)
-
- assert_equivalent [c1,c2], scope
- end
-
- should 'provide a scope based on the environment' do
- alt_environment = fast_create(Environment)
- c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
- c2 = ProductCategory.create!(:name => 'test cat 2', :environment => alt_environment)
- c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
-
- scope = ProductCategory.by_environment(alt_environment)
-
- assert_equivalent [c2], scope
- assert_equivalent [c1,c3], ProductCategory.by_environment(Environment.default)
- end
-
-end
diff --git a/test/unit/product_test.rb b/test/unit/product_test.rb
deleted file mode 100644
index 2cce599..0000000
--- a/test/unit/product_test.rb
+++ /dev/null
@@ -1,634 +0,0 @@
-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
diff --git a/test/unit/production_cost_test.rb b/test/unit/production_cost_test.rb
deleted file mode 100644
index 15017a9..0000000
--- a/test/unit/production_cost_test.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-require_relative "../test_helper"
-
-class ProductionCostTest < ActiveSupport::TestCase
-
- should 'have name' do
- p = ProductionCost.new
- p.valid?
- assert p.errors[:name.to_s].present?
-
- p.name = 'Taxes'
- p.valid?
- refute p.errors[:name.to_s].present?
- end
-
- should 'not validates name if it is blank' do
- p = ProductionCost.new
-
- p.valid?
- assert_equal 1, p.errors['name'].to_a.count
- end
-
- should 'not have a too long name' do
- p = ProductionCost.new
-
- p.name = 'a'*40
- p.valid?
- assert p.errors[:name.to_s].present?
-
- p.name = 'a'*30
- p.valid?
- refute p.errors[:name.to_s].present?
- end
-
- should 'not have duplicated name on same environment' do
- cost = create(ProductionCost, :name => 'Taxes', :owner => Environment.default)
-
- invalid_cost = build(ProductionCost, :name => 'Taxes', :owner => Environment.default)
- invalid_cost.valid?
-
- assert invalid_cost.errors[:name.to_s].present?
- end
-
- should 'not have duplicated name on same enterprise' do
- enterprise = fast_create(Enterprise)
- cost = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
-
- invalid_cost = build(ProductionCost, :name => 'Taxes', :owner => enterprise)
- invalid_cost.valid?
-
- assert invalid_cost.errors[:name.to_s].present?
- end
-
- should 'not allow same name on enterprise if already has on environment' do
- enterprise = fast_create(Enterprise)
-
- cost1 = create(ProductionCost, :name => 'Taxes', :owner => Environment.default)
- cost2 = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
-
- cost2.valid?
-
- refute cost2.errors[:name.to_s].present?
- end
-
- should 'allow duplicated name on different enterprises' do
- enterprise = fast_create(Enterprise)
- enterprise2 = fast_create(Enterprise)
-
- cost1 = create(ProductionCost, :name => 'Taxes', :owner => enterprise)
- cost2 = build(ProductionCost, :name => 'Taxes', :owner => enterprise2)
-
- cost2.valid?
-
- refute cost2.errors[:name.to_s].present?
- end
-
- should 'be associated to an environment as owner' do
- p = ProductionCost.new
- p.valid?
- assert p.errors[:owner.to_s].present?
-
- p.owner = Environment.default
- p.valid?
- refute p.errors[:owner.to_s].present?
- end
-
- should 'be associated to an enterprise as owner' do
- enterprise = fast_create(Enterprise)
- p = ProductionCost.new
- p.valid?
- assert p.errors[:owner.to_s].present?
-
- p.owner = enterprise
- p.valid?
- refute p.errors[:owner.to_s].present?
- end
-
- should 'create a production cost on an enterprise' do
- enterprise = fast_create(Enterprise)
- create(ProductionCost, :name => 'Energy', :owner => enterprise)
- assert_equal ['Energy'], enterprise.production_costs.map(&:name)
- end
-end
diff --git a/test/unit/products_block_test.rb b/test/unit/products_block_test.rb
deleted file mode 100644
index c3825c5..0000000
--- a/test/unit/products_block_test.rb
+++ /dev/null
@@ -1,175 +0,0 @@
-require_relative "../test_helper"
-
-class ProductsBlockTest < ActiveSupport::TestCase
-
- def setup
- @block = ProductsBlock.new
- @product_category = fast_create(ProductCategory, :name => 'Products')
- end
- attr_reader :block
-
- should 'be inherit from block' do
- assert_kind_of Block, block
- end
-
- should 'provide default title' do
- assert_not_equal Block.new.default_title, ProductsBlock.new.default_title
- end
-
- should 'provide default description' do
- assert_not_equal Block.description, ProductsBlock.description
- end
-
- should 'list 4 random products by default' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product five', :product_category => @product_category)
-
- block.stubs(:owner).returns(enterprise)
-
- assert_equal 4, block.products.size
- end
-
- should 'list all products if less than 4 by default' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
-
- block.stubs(:owner).returns(enterprise)
-
- assert_equal 3, block.products.size
- end
-
-
- should 'be able to set product_ids and have them listed' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
- p3 = create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
- p4 = create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
- p5 = create(Product, :enterprise => enterprise, :name => 'product five', :product_category => @product_category)
-
- block.stubs(:owner).returns(enterprise)
-
- block.product_ids = [p1, p3, p5].map(&:id)
- assert_equivalent [p1, p3, p5], block.products
- end
-
- should 'save product_ids' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
-
- block = ProductsBlock.new
- enterprise.boxes.first.blocks << block
- block.product_ids = [p1.id, p2.id]
- block.save!
-
- assert_equal [p1.id, p2.id], ProductsBlock.find(block.id).product_ids
- end
-
- should 'accept strings in product_ids but store integers' do
- block = ProductsBlock.new
- block.product_ids = [ '1', '2']
- assert_equal [1, 2], block.product_ids
- end
-
- should 'not repeat products' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- p1 = create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- p2 = create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
- p3 = create(Product, :enterprise => enterprise, :name => 'product three', :product_category => @product_category)
- p4 = create(Product, :enterprise => enterprise, :name => 'product four', :product_category => @product_category)
-
- block = ProductsBlock.new
- enterprise.boxes.first.blocks << block
- block.save!
-
- 4.times do # to keep a minimal chance of false positive, its random after all
- assert_equivalent [p1, p2, p3, p4], block.products
- end
- end
-end
-
-require 'boxes_helper'
-require 'block_helper'
-
-class ProductsBlockViewTest < ActionView::TestCase
- include BoxesHelper
-
- ActionView::Base.send :include, BlockHelper
-
- def setup
- @block = ProductsBlock.new
- @product_category = fast_create(ProductCategory, :name => 'Products')
- end
- attr_reader :block
-
- should "list owner products" do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
-
- block.expects(:products).returns(enterprise.products)
-
- content = render_block_content(block)
-
- assert_tag_in_string content, :content => 'Products'
-
- assert_tag_in_string content, :tag => 'li', :attributes => { :class => 'product' }, :descendant => { :tag => 'a', :content => /product one/ }
- assert_tag_in_string content, :tag => 'li', :attributes => { :class => 'product' }, :descendant => { :tag => 'a', :content => /product two/ }
- end
-
- should 'display the default minor image if thumbnails were not processed' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')})
-
- block.expects(:products).returns(enterprise.products)
- ActionView::Base.any_instance.stubs(:block_title).returns("")
-
- content = render_block_content(block)
-
- assert_tag_in_string content, :tag => 'a', :attributes => { :style => /image-loading-minor.png/ }
- end
-
- should 'display the thumbnail image if thumbnails were processed' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product', :product_category => @product_category, :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')})
-
- process_delayed_job_queue
- block.expects(:products).returns(enterprise.products.reload)
- ActionView::Base.any_instance.stubs(:block_title).returns("")
-
- content = render_block_content(block)
- assert_tag_in_string content, :tag => 'a', :attributes => { :style => /rails_minor.png/ }
- end
-
- should 'point to all products in footer' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
-
- block.stubs(:owner).returns(enterprise)
-
- footer = render_block_footer(block)
-
- assert_tag_in_string footer, :tag => 'a', :attributes => { :href => /\/catalog\/testenterprise$/ }, :content => 'View all products'
- end
-
- should 'generate footer when enterprise has own hostname' do
- enterprise = create(Enterprise, :name => 'testenterprise', :identifier => 'testenterprise')
- enterprise.domains << Domain.new(:name => 'sometest.com'); enterprise.save!
- create(Product, :enterprise => enterprise, :name => 'product one', :product_category => @product_category)
- create(Product, :enterprise => enterprise, :name => 'product two', :product_category => @product_category)
-
- block.stubs(:owner).returns(enterprise)
-
- footer = render_block_footer(block)
-
- assert_tag_in_string footer, :tag => 'a', :attributes => { :href => /\/catalog\/testenterprise$/ }, :content => 'View all products'
- end
-end
diff --git a/test/unit/profile_image_helper_test.rb b/test/unit/profile_image_helper_test.rb
index 9d27cf3..c92ac54 100644
--- a/test/unit/profile_image_helper_test.rb
+++ b/test/unit/profile_image_helper_test.rb
@@ -70,7 +70,7 @@ class ProfileImageHelperTest < ActionView::TestCase
enterprise.stubs(:public_profile_url).returns('url for enterprise')
stubs(:catalog_path)
links = links_for_balloon(enterprise)
- assert_equal ['Products', 'Members', 'Agenda', 'Send an e-mail'], links.map{|i| i.keys.first}
+ assert_equal ['Members', 'Agenda', 'Send an e-mail'], links.map{|i| i.keys.first}
end
should 'not return mime type of profile icon if not requested' do
diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb
index 538d1de..0268d1a 100644
--- a/test/unit/profile_test.rb
+++ b/test/unit/profile_test.rb
@@ -653,10 +653,6 @@ class ProfileTest < ActiveSupport::TestCase
assert_includes profile.categories_including_virtual(true), pcat
end
- should 'not accept product category as category' do
- refute Profile.new.accept_category?(ProductCategory.new)
- end
-
should 'not accept region as a category' do
refute Profile.new.accept_category?(Region.new)
end
diff --git a/test/unit/qualifier_certifier_test.rb b/test/unit/qualifier_certifier_test.rb
deleted file mode 100644
index 7baa85f..0000000
--- a/test/unit/qualifier_certifier_test.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative "../test_helper"
-
-class QualifierCertifierTest < ActiveSupport::TestCase
-
- should 'connect certifiers and qualifiers' do
- env_one = fast_create(Environment)
- qualifier = env_one.qualifiers.create(:name => 'Qualifier')
- certifier = env_one.certifiers.create(:name => 'Certifier')
-
- QualifierCertifier.new.tap do |qc|
- qc.qualifier = qualifier
- qc.certifier = certifier
- end.save!
-
- assert_includes certifier.qualifiers, qualifier
- assert_includes qualifier.certifiers, certifier
- end
-
-end
diff --git a/test/unit/qualifier_test.rb b/test/unit/qualifier_test.rb
deleted file mode 100644
index 70f0513..0000000
--- a/test/unit/qualifier_test.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# encoding: UTF-8
-require_relative "../test_helper"
-
-class QualifierTest < ActiveSupport::TestCase
-
- should 'environment is mandatory' do
- qualifier = Qualifier.new(:name => 'Qualifier without environment')
- refute qualifier.valid?
-
- qualifier.environment = fast_create(Environment)
- assert qualifier.valid?
- end
-
- should 'belongs to environment' do
- env_one = fast_create(Environment)
- qualifier_from_env_one = env_one.qualifiers.create(:name => 'Qualifier from environment one')
-
- env_two = fast_create(Environment)
- qualifier_from_env_two = env_two.qualifiers.create(:name => 'Qualifier from environment two')
-
- assert_includes env_one.qualifiers, qualifier_from_env_one
- assert_not_includes env_one.qualifiers, qualifier_from_env_two
- end
-
- should 'name is mandatory' do
- env_one = fast_create(Environment)
- qualifier = env_one.qualifiers.build
- refute qualifier.valid?
-
- qualifier.name = 'Qualifier name'
- assert qualifier.valid?
- end
-
- should 'sort by name' do
- last = fast_create(Qualifier, :name => "Zumm")
- first = fast_create(Qualifier, :name => "Atum")
- assert_equal [first, last], Qualifier.all.sort
- end
-
- should 'sorting is not case sensitive' do
- first = fast_create(Qualifier, :name => "Aaaa")
- second = fast_create(Qualifier, :name => "abbb")
- last = fast_create(Qualifier, :name => "Accc")
- assert_equal [first, second, last], Qualifier.all.sort
- end
-
- should 'discard non-ascii char when sorting' do
- first = fast_create(Qualifier, :name => "Áaaa")
- last = fast_create(Qualifier, :name => "Aáab")
- assert_equal [first, last], Qualifier.all.sort
- end
-
- should 'clean all ProductQualifier when destroy a Qualifier' do
- product1 = fast_create(Product)
- product2 = fast_create(Product)
- qualifier = fast_create(Qualifier, :name => 'Free Software')
- certifier = fast_create(Certifier, :name => 'FSF')
- ProductQualifier.create!(:product => product1, :qualifier => qualifier, :certifier => certifier)
- ProductQualifier.create!(:product => product2, :qualifier => qualifier, :certifier => certifier)
- assert_equal [['Free Software', 'FSF']], product1.product_qualifiers.map{|i| [i.qualifier.name, i.certifier.name]}
- Qualifier.destroy_all
- assert_equal [], product1.product_qualifiers(true)
- end
-end
diff --git a/test/unit/search_helper_test.rb b/test/unit/search_helper_test.rb
index 63f7983..77d0e34 100644
--- a/test/unit/search_helper_test.rb
+++ b/test/unit/search_helper_test.rb
@@ -6,32 +6,9 @@ class SearchHelperTest < ActiveSupport::TestCase
include ActionView::Helpers::FormOptionsHelper
include ActionView::Helpers::FormTagHelper
-
- should 'return whether on a multiple search' do
- stubs(:params).returns({:action => 'index', :display => 'map'})
- @results = {:articles => [1,2], :products => [1,2]}
- assert multiple_search?
-
- stubs(:params).returns({:action => 'products', :display => 'map'})
- @results = {:products => [1,2]}
- refute multiple_search?
- end
-
- should 'return whether on a map search' do
- stubs(:params).returns({:action => 'index', :display => 'map'})
- @results = {:articles => [1,2], :products => [1,2]}
- @query = ''
- refute map_search?
-
- stubs(:params).returns({:action => 'products', :display => 'map'})
- @results = {:products => [1,2]}
- @query = 'test'
- assert map_search?
- end
-
should 'display search page title' do
title = 'page_title'
- assert_equal search_page_title(title), 'page_title '
+ assert_equal search_page_title(title), 'page_title '
end
should 'display search page title with category name' do
@@ -61,10 +38,10 @@ class SearchHelperTest < ActiveSupport::TestCase
should 'display results with map' do
stubs(:params).returns({:display => 'map'})
@query = 'test'
- @searches = {:products => {:results => [1,2]}}
+ @searches = {:enterprises => {:results => [1,2]}}
expects('render').with({:partial => 'google_maps'}).returns('render_return')
expects('content_tag').with('div', 'render_return', :class => 'map-or-list-search-results map')
- display_results(@searches, :products)
+ display_results(@searches, :enterprises)
end
should 'return full city name with state' do
@@ -116,10 +93,10 @@ class SearchHelperTest < ActiveSupport::TestCase
city.stubs(:name).returns('Feliz Deserto')
assert_equal 'Feliz Deserto', city_with_state(city)
end
-
+
should 'return asset class from string' do
- asset_names = ['products', 'events', 'articles', 'enterprises', 'people', 'communities']
- asset_classes = [Product, Event, Article, Enterprise, Person, Community]
+ asset_names = ['events', 'articles', 'enterprises', 'people', 'communities']
+ asset_classes = [Event, Article, Enterprise, Person, Community]
asset_names.each_index do |i|
assert_equal asset_classes[i], asset_class(asset_names[i])
end
diff --git a/test/unit/sellers_search_block_test.rb b/test/unit/sellers_search_block_test.rb
deleted file mode 100644
index e8b724b..0000000
--- a/test/unit/sellers_search_block_test.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative "../test_helper"
-
-class SellersSearchBlockTest < ActiveSupport::TestCase
-
- should 'provide description' do
- assert_not_equal Block.description, SellersSearchBlock.description
- end
-
- should 'provide default title' do
- assert_not_equal Block.new.default_title, SellersSearchBlock.new.default_title
- end
-
-end
diff --git a/test/unit/unit_test.rb b/test/unit/unit_test.rb
deleted file mode 100644
index 0a11474..0000000
--- a/test/unit/unit_test.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative "../test_helper"
-
-class UnitTest < ActiveSupport::TestCase
-
- should 'require singular name' do
- unit = Unit.new; unit.valid?
- assert_match /can't be blank/, unit.errors["singular"].first
- end
-
- should 'require plural name' do
- unit = Unit.new; unit.valid?
- assert_match /can't be blank/, unit.errors["plural"].first
- end
-
- should 'belongs and require an environment' do
- unit = Unit.new; unit.valid?
- assert_match /can't be blank/, unit.errors["environment_id"].first
- unit.environment = Environment.default; unit.valid?
- assert_nil unit.errors["environment_id"].first
- end
-
- should 'increment position automatically' do
- first = Unit.new(:singular => 'Litre', :plural => 'Litres').tap do |u|
- u.environment = Environment.default
- u.save!
- end
- second = Unit.new(:singular => 'Meter', :plural => 'Meters').tap do |u|
- u.environment = Environment.default
- u.save!
- end
- assert_equal 1, first.position
- assert_equal 2, second.position
- end
-
- should 'has an getter and setter alias to singular field' do
- unit = Unit.new(:name => 'Litre')
- assert_equal 'Litre', unit.singular
- end
-
-end
--
libgit2 0.21.2