Commit 31868a1af19ba6c59d9c2fe104c7328a20772ab0

Authored by Braulio Bhavamitra
1 parent bb150fb8

Move products into a plugin

This will many further improvements to the products, such as:
- Interaction with other plugins such as suppliers, stock and
currencies. The inteface can change in such a way that if done
usings hotspots would hurt usability and coherence.
- More autonomy to develop and integrate other features
(in the next months we will integrate batch edition and stock,
currencies might come next)
- More declouping from core and other components
Showing 299 changed files with 8263 additions and 7886 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 299 files displayed.

app/controllers/admin/categories_controller.rb
... ... @@ -7,7 +7,6 @@ class CategoriesController < AdminController
7 7 def index
8 8 @categories = environment.categories.where("parent_id is null AND type is null")
9 9 @regions = environment.regions.where(:parent_id => nil)
10   - @product_categories = environment.product_categories.where(:parent_id => nil)
11 10 end
12 11  
13 12 def get_children
... ...
app/controllers/admin/edit_template_controller.rb
1 1 class EditTemplateController < AdminController
2   -
  2 +
3 3 protect 'edit_environment_design', :environment
4   -
  4 +
5 5 #FIXME
6 6 #design_editor :holder => 'environment', :autosave => true, :block_types => :block_types
7 7  
... ... @@ -9,7 +9,6 @@ class EditTemplateController &lt; AdminController
9 9 %w[
10 10 FavoriteLinks
11 11 ListBlock
12   - SellersSearchBlock
13 12 ]
14 13 end
15 14  
... ...
app/controllers/admin/environment_design_controller.rb
1 1 class EnvironmentDesignController < BoxOrganizerController
2   -
  2 +
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
6   - @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
  6 + @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7 7 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
8 8 end
9 9  
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -409,9 +409,6 @@ class CmsController &lt; MyProfileController
409 409 ]
410 410 articles += special_article_types if params && params[:cms]
411 411 parent_id = params ? params[:parent_id] : nil
412   - if profile.enterprise?
413   - articles << EnterpriseHomepage
414   - end
415 412 if @parent && @parent.blog?
416 413 articles -= Article.folder_types.map(&:constantize)
417 414 end
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -1,229 +0,0 @@
1   -class ManageProductsController < ApplicationController
2   - needs_profile
3   -
4   - protect 'manage_products', :profile, :except => [:show]
5   - before_filter :check_environment_feature
6   - before_filter :login_required, :except => [:show]
7   - before_filter :create_product?, :only => [:new]
8   -
9   - protected
10   -
11   - def check_environment_feature
12   - unless profile.environment.enabled?('products_for_enterprises')
13   - render_not_found
14   - return
15   - end
16   - end
17   -
18   - def create_product?
19   - if !profile.create_product?
20   - render_access_denied
21   - return
22   - end
23   - end
24   -
25   - public
26   -
27   - def index
28   - @products = @profile.products.paginate(:per_page => 10, :page => params[:page])
29   - end
30   -
31   - def show
32   - @product = @profile.products.find(params[:id])
33   - @inputs = @product.inputs
34   - @allowed_user = user && user.has_permission?('manage_products', profile)
35   - end
36   -
37   - def categories_for_selection
38   - @category = environment.categories.find_by id: params[:category_id]
39   - @object_name = params[:object_name]
40   - if @category
41   - @categories = @category.children
42   - @level = @category.leaf? ? @category.level : @categories.first.level
43   - else
44   - @categories = ProductCategory.top_level_for(environment)
45   - @level = 0
46   - end
47   - render :partial => 'categories_for_selection', :locals => { :categories => @categories, :level => @level }
48   - end
49   -
50   - def new
51   - @no_design_blocks = true
52   - @category = params[:selected_category_id] ? Category.find(params[:selected_category_id]) : nil
53   - @product = @profile.products.build(:product_category => @category)
54   - @categories = ProductCategory.top_level_for(environment)
55   - @level = 0
56   - if request.post?
57   - if @product.save
58   - session[:notice] = _('Product succesfully created')
59   - render :partial => 'shared/redirect_via_javascript',
60   - :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
61   - else
62   - render_dialog_error_messages 'product'
63   - end
64   - end
65   - end
66   -
67   - def edit
68   - @product = @profile.products.find(params[:id])
69   - field = params[:field]
70   - if request.post?
71   - begin
72   - @product.update!(params[:product])
73   - render :partial => "display_#{field}", :locals => {:product => @product}
74   - rescue Exception => e
75   - render :partial => "edit_#{field}", :locals => {:product => @product, :errors => true}
76   - end
77   - else
78   - render :partial => "edit_#{field}", :locals => {:product => @product, :errors => false}
79   - end
80   - end
81   -
82   - def edit_category
83   - @product = @profile.products.find(params[:id])
84   - @category = @product.product_category || ProductCategory.first
85   - @categories = ProductCategory.top_level_for(environment)
86   - @edit = true
87   - @level = @category.level
88   - if request.post?
89   - if @product.update({:product_category_id => params[:selected_category_id]}, :without_protection => true)
90   - render :partial => 'shared/redirect_via_javascript',
91   - :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
92   - else
93   - render_dialog_error_messages 'product'
94   - end
95   - end
96   - end
97   -
98   - def show_category_tree
99   - @category = environment.categories.find params[:category_id]
100   - render :partial => 'selected_category_tree'
101   - end
102   -
103   - def search_categories
104   - @term = params[:term].downcase
105   - conditions = ['LOWER(name) LIKE ? OR LOWER(name) LIKE ?', "#{@term}%", "% #{@term}%"]
106   - @categories = ProductCategory.where(conditions).limit(10)
107   - render :json => (@categories.map do |category|
108   - {:label => category.name, :value => category.id}
109   - end)
110   - end
111   -
112   - def add_input
113   - @product = @profile.products.find(params[:id])
114   - @input = @product.inputs.build
115   - @categories = ProductCategory.top_level_for(environment)
116   - @level = 0
117   - if request.post?
118   - if @input.update(:product_category_id => params[:selected_category_id])
119   - @inputs = @product.inputs
120   - render :partial => 'display_inputs'
121   - else
122   - render_dialog_error_messages 'product'
123   - end
124   - else
125   - render :partial => 'add_input'
126   - end
127   - end
128   -
129   - def manage_product_details
130   - @product = @profile.products.find(params[:id])
131   - if request.post?
132   - @product.update_price_details(params[:price_details]) if params[:price_details]
133   - render :partial => 'display_price_details'
134   - else
135   - render :partial => 'manage_product_details'
136   - end
137   - end
138   -
139   - def remove_price_detail
140   - @product = @profile.products.find(params[:product])
141   - @price_detail = @product.price_details.find(params[:id])
142   - @product = @price_detail.product
143   - if request.post?
144   - @price_detail.destroy
145   - render :nothing => true
146   - end
147   - end
148   -
149   - def display_price_composition_bar
150   - @product = @profile.products.find(params[:id])
151   - render :partial => 'price_composition_bar'
152   - end
153   -
154   - def display_inputs_cost
155   - @product = @profile.products.find(params[:id])
156   - render :inline => "<%= float_to_currency(@product.inputs_cost) %>"
157   - end
158   -
159   - def destroy
160   - @product = @profile.products.find(params[:id])
161   - if @product.destroy
162   - session[:notice] = _('Product succesfully removed')
163   - redirect_back_or_default :action => 'index'
164   - else
165   - session[:notice] = _('Could not remove the product')
166   - redirect_back_or_default :action => 'show', :id => @product
167   - end
168   - end
169   -
170   - def edit_input
171   - if request.xhr?
172   - @input = @profile.inputs.find_by id: params[:id]
173   - if @input
174   - if request.post?
175   - if @input.update(params[:input])
176   - render :partial => 'display_input', :locals => {:input => @input}
177   - else
178   - render :partial => 'edit_input'
179   - end
180   - else
181   - render :partial => 'edit_input'
182   - end
183   - else
184   - render :text => _('The input was not found')
185   - end
186   - end
187   - end
188   -
189   - def order_inputs
190   - @product = @profile.products.find(params[:id])
191   - @product.order_inputs!(params[:input]) if params[:input]
192   - render :nothing => true
193   - end
194   -
195   - def remove_input
196   - @input = @profile.inputs.find(params[:id])
197   - @product = @input.product
198   - if request.post?
199   - if @input.destroy
200   - @inputs = @product.inputs
201   - render :partial => 'display_inputs'
202   - else
203   - render_dialog_error_messages 'input'
204   - end
205   - end
206   - end
207   -
208   - def certifiers_for_selection
209   - @qualifier = Qualifier.exists?(:id => params[:id]) ? Qualifier.find(params[:id]) : nil
210   - render :update do |page|
211   - page.replace_html params[:certifier_area], :partial => 'certifiers_for_selection'
212   - end
213   - end
214   -
215   - def create_production_cost
216   - cost = @profile.production_costs.create(:name => params[:id])
217   - if cost.valid?
218   - cost.save
219   - render :text => {:name => cost.name,
220   - :id => cost.id,
221   - :ok => true
222   - }.to_json
223   - else
224   - render :text => {:ok => false,
225   - :error_msg => _(cost.errors['name'].join('\n')) % {:fn => _('Name')}
226   - }.to_json
227   - end
228   - end
229   -end
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -45,17 +45,10 @@ class ProfileDesignController &lt; BoxOrganizerController
45 45 if profile.enterprise?
46 46 blocks << DisabledEnterpriseMessageBlock
47 47 blocks << HighlightsBlock
48   - blocks << ProductCategoriesBlock
49   - blocks << FeaturedProductsBlock
50 48 blocks << FansBlock
51 49 blocks += plugins.dispatch(:extra_blocks, :type => Enterprise)
52 50 end
53 51  
54   - # product block exclusive for enterprises in environments that permits it
55   - if profile.enterprise? && profile.environment.enabled?('products_for_enterprises')
56   - blocks << ProductsBlock
57   - end
58   -
59 52 # block exclusive to profiles that have blog
60 53 if profile.has_blog?
61 54 blocks << BlogArchivesBlock
... ...
app/controllers/public/catalog_controller.rb
... ... @@ -1,19 +0,0 @@
1   -class CatalogController < PublicController
2   - needs_profile
3   -
4   - before_filter :check_enterprise_and_environment
5   -
6   - def index
7   - extend CatalogHelper
8   - catalog_load_index
9   - end
10   -
11   - protected
12   -
13   - def check_enterprise_and_environment
14   - unless profile.enterprise? && @profile.environment.enabled?('products_for_enterprises')
15   - redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index'
16   - end
17   - end
18   -
19   -end
app/controllers/public/search_controller.rb
... ... @@ -52,7 +52,6 @@ class SearchController &lt; PublicController
52 52 [
53 53 [ :people, _('People'), :recent_people ],
54 54 [ :enterprises, _('Enterprises'), :recent_enterprises ],
55   - [ :products, _('Products'), :recent_products ],
56 55 [ :events, _('Upcoming events'), :upcoming_events ],
57 56 [ :communities, _('Communities'), :recent_communities ],
58 57 [ :articles, _('Contents'), :recent_articles ]
... ... @@ -78,16 +77,17 @@ class SearchController &lt; PublicController
78 77 full_text_search
79 78 end
80 79  
81   - def products
82   - @scope = @environment.products
83   - full_text_search
84   - end
85   -
86 80 def enterprises
87 81 @scope = visible_profiles(Enterprise)
88 82 full_text_search
89 83 end
90 84  
  85 + # keep URL compatibility
  86 + def products
  87 + return render_not_found unless defined? ProductsPlugin
  88 + redirect_to url_for(params.merge controller: 'products_plugin/search', action: :products)
  89 + end
  90 +
91 91 def communities
92 92 @scope = visible_profiles(Community)
93 93 full_text_search
... ... @@ -186,7 +186,6 @@ class SearchController &lt; PublicController
186 186 people: _('People'),
187 187 communities: _('Communities'),
188 188 enterprises: _('Enterprises'),
189   - products: _('Products and Services'),
190 189 events: _('Events'),
191 190 }
192 191 end
... ... @@ -260,12 +259,11 @@ class SearchController &lt; PublicController
260 259 end
261 260  
262 261 def available_assets
263   - assets = {
  262 + {
264 263 articles: _('Contents'),
265 264 enterprises: _('Enterprises'),
266 265 people: _('People'),
267 266 communities: _('Communities'),
268   - products: _('Products and Services'),
269 267 }
270 268 end
271 269  
... ...
app/helpers/action_tracker_helper.rb
... ... @@ -67,24 +67,6 @@ module ActionTrackerHelper
67 67 }
68 68 end
69 69  
70   - def create_product_description ta
71   - _('created the product %{title}') % {
72   - title: link_to(truncate(ta.get_name), ta.get_url),
73   - }
74   - end
75   -
76   - def update_product_description ta
77   - _('updated the product %{title}') % {
78   - title: link_to(truncate(ta.get_name), ta.get_url),
79   - }
80   - end
81   -
82   - def remove_product_description ta
83   - _('removed the product %{title}') % {
84   - title: truncate(ta.get_name),
85   - }
86   - end
87   -
88 70 def favorite_enterprise_description ta
89 71 _('favorited enterprise %{title}') % {
90 72 title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url),
... ...
app/helpers/application_helper.rb
... ... @@ -44,8 +44,6 @@ module ApplicationHelper
44 44  
45 45 include TokenHelper
46 46  
47   - include CatalogHelper
48   -
49 47 include PluginsHelper
50 48  
51 49 include ButtonsHelper
... ... @@ -787,7 +785,7 @@ module ApplicationHelper
787 785 return "" if categories.blank?
788 786 content_tag(:ul) do
789 787 categories.map do |category|
790   - category_path = category.kind_of?(ProductCategory) ? {:controller => 'search', :action => 'assets', :asset => 'products', :product_category => category.id} : { :controller => 'search', :action => 'category_index', :category_path => category.explode_path }
  788 + category_path = { :controller => 'search', :action => 'category_index', :category_path => category.explode_path }
791 789 if category.display_in_menu?
792 790 content_tag(:li) do
793 791 if !category.is_leaf_displayable_in_menu?
... ...
app/helpers/catalog_helper.rb
... ... @@ -1,45 +0,0 @@
1   -module CatalogHelper
2   -
3   - include DisplayHelper
4   - include ManageProductsHelper
5   -
6   - def catalog_load_index options = {:page => params[:page], :show_categories => true}
7   - if options[:show_categories]
8   - @category = params[:level] ? ProductCategory.find(params[:level]) : nil
9   - @categories = ProductCategory.on_level(params[:level]).order(:name)
10   - end
11   -
12   - @products = profile.products.from_category(@category).
13   - reorder('available desc, highlighted desc, name asc').
14   - paginate(:per_page => @profile.products_per_catalog_page, :page => options[:page])
15   - end
16   -
17   - def breadcrumb(category)
18   - start = link_to(_('Start'), {:controller => :catalog, :action => 'index'})
19   - ancestors = category.ancestors.map { |c| link_to(c.name, {:controller => :catalog, :action => 'index', :level => c.id}) }.reverse
20   - current_level = content_tag('strong', category.name)
21   - all_items = [start] + ancestors + [current_level]
22   - content_tag('div', safe_join(all_items, ' &rarr; '), :id => 'breadcrumb')
23   - end
24   -
25   - def category_link(category)
26   - count = profile.products.from_category(category).count
27   - name = truncate(category.name, :length => 22 - count.to_s.size)
28   - link = link_to(name, {:controller => 'catalog', :action => 'index', :level => category.id}, :title => category.name)
29   - content_tag('div', "#{link} <span class=\"count\">#{count}</span>".html_safe) if count > 0
30   - end
31   -
32   - def category_with_sub_list(category)
33   - content_tag 'li', "#{category_link(category)}\n#{sub_category_list(category)}".html_safe
34   - end
35   -
36   - def sub_category_list(category)
37   - sub_categories = []
38   - category.children.order(:name).each do |sub_category|
39   - cat_link = category_link sub_category
40   - sub_categories << content_tag('li', cat_link) unless cat_link.nil?
41   - end
42   - content_tag('ul', sub_categories.join.html_safe) if sub_categories.size > 0
43   - end
44   -
45   -end
app/helpers/categories_helper.rb
... ... @@ -2,7 +2,6 @@ module CategoriesHelper
2 2  
3 3 TYPES = [
4 4 [ _('General Category'), Category.to_s ],
5   - [ _('Product Category'), ProductCategory.to_s ],
6 5 [ _('Region'), Region.to_s ],
7 6 ]
8 7  
... ...
app/helpers/display_helper.rb
1 1 module DisplayHelper
2 2  
3   - def link_to_product(product, opts={})
4   - return _('No product') unless product
5   - target = product_path(product)
6   - link_to content_tag( 'span', product.name ),
7   - target,
8   - opts
9   - end
10   -
11 3 def themed_path(file)
12 4 if File.exists?(File.join(Rails.root, 'public', theme_path, file))
13 5 File.join(theme_path, file)
... ... @@ -16,42 +8,21 @@ module DisplayHelper
16 8 end
17 9 end
18 10  
19   - def image_link_to_product(product, opts={})
20   - return _('No product') unless product
21   - target = product_path(product)
22   - link_to image_tag(product.default_image(:big), :alt => product.name),
23   - target,
24   - opts
25   - end
26   -
27 11 def price_span(price, options = {})
28 12 content_tag 'span',
29 13 number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator),
30 14 options
31 15 end
32 16  
33   - def product_path(product)
34   - product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url
35   - end
36   -
37 17 def link_to_tag(tag, html_options = {})
38 18 link_to tag.name, {:controller => 'search', :action => 'tag', :tag => tag.name}, html_options
39 19 end
40 20  
41 21 def link_to_category(category, full = true, html_options = {})
42   - return _('Uncategorized product') unless category
43 22 name = full ? category.full_name(' &rarr; ') : category.name
44 23 link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }), html_options
45 24 end
46 25  
47   - def link_to_product_category(category)
48   - if category
49   - link_to(category.name, :controller => 'search', :action => 'products', :category_path => category.explode_path)
50   - else
51   - _('Uncategorized product')
52   - end
53   - end
54   -
55 26 def txt2html(txt)
56 27 ret = txt.strip.
57 28 gsub( /\s*\n\s*\n\s*/, "\r<p/>\r" ).
... ...
app/helpers/enterprise_homepage_helper.rb
... ... @@ -1,25 +0,0 @@
1   -module EnterpriseHomepageHelper
2   -
3   - def display_profile_info(profile)
4   - data = ''
5   - [
6   - [ _('Contact person:'), :contact_person ],
7   - [ _('e-Mail:'), :contact_email ],
8   - [ _('Phone(s):'), :contact_phone ],
9   - [ _('Location:'), :location ],
10   - [ _('Address:'), :address ],
11   - [ _('Economic activity:'), :economic_activity ]
12   - ].each { | name, att |
13   - if profile.send( att ) and not profile.send( att ).blank?
14   - data << content_tag( 'li', content_tag('strong', name) +' '+ profile.send( att ).to_s ) +"\n"
15   - end
16   - }
17   - if profile.respond_to?(:distance) and !profile.distance.nil?
18   - data << content_tag( 'li',
19   - content_tag('strong',_('Distance:')) +' '+
20   - "%.2f%" % profile.distance
21   - ) + "\n"
22   - end
23   - content_tag('div', content_tag('ul', data), :class => 'enterprise-info')
24   - end
25   -end
app/helpers/manage_products_helper.rb
... ... @@ -1,289 +0,0 @@
1   -# encoding: UTF-8
2   -
3   -module ManageProductsHelper
4   -
5   - def remote_function_to_update_categories_selection(container_id, options = {})
6   - remote_function({
7   - :update => container_id,
8   - :url => { :action => "categories_for_selection" },
9   - :loading => "loading('hierarchy_navigation', '#{ _('loading…') }'); loading('#{container_id}', '&nbsp;')",
10   - :complete => "loading_done('hierarchy_navigation'); loading_done('#{container_id}')"
11   - }.merge(options))
12   - end
13   -
14   - def hierarchy_category_item(category, make_links, title = nil)
15   - title ||= category.name
16   - if make_links
17   - link_to(title, '#',
18   - :title => title,
19   - :onclick => remote_function_to_update_categories_selection("categories_container_level#{ category.level + 1 }",
20   - :with => "'category_id=#{ category.id }'"
21   - )
22   - )
23   - else
24   - title
25   - end
26   - end
27   -
28   - def hierarchy_category_navigation(current_category, options = {})
29   - hierarchy = []
30   - if current_category
31   - hierarchy << current_category.name unless options[:hide_current_category]
32   - ancestors = current_category.ancestors
33   - ancestors.each do |category|
34   - hierarchy << hierarchy_category_item(category, options[:make_links])
35   - end
36   - end
37   - hierarchy.reverse.join(options[:separator] || ' &rarr; ')
38   - end
39   -
40   - def options_for_select_categories(categories, selected = nil)
41   - safe_join(categories.sort_by{ |cat|
42   - cat.name.transliterate}.map do |category|
43   - selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '')
44   - "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{category.name + (category.leaf? ? '': ' &raquo;')}</option>".html_safe
45   - end, "\n")
46   - end
47   -
48   - def build_selects_for_ancestors(ancestors, current_category)
49   - current_ancestor = ancestors.shift
50   - if current_ancestor.nil?
51   - select_for_new_category(current_category.children, current_category.level + 1)
52   - else
53   - content_tag('div',
54   - select_tag('category_id',
55   - options_for_select_categories(current_ancestor.siblings + [current_ancestor], current_ancestor),
56   - :size => 10,
57   - :onchange => remote_function_to_update_categories_selection("categories_container_level#{ current_ancestor.level + 1 }", :with => "'category_id=' + this.value")
58   - ) +
59   - build_selects_for_ancestors(ancestors, current_category),
60   - :class => 'categories_container',
61   - :id => "categories_container_level#{ current_ancestor.level }"
62   - )
63   - end
64   - end
65   -
66   - def selects_for_all_ancestors(current_category)
67   - build_selects_for_ancestors(current_category.ancestors.reverse + [current_category], current_category)
68   - end
69   -
70   - def select_for_new_category(categories, level)
71   - content_tag('div',
72   - render(:partial => 'categories_for_selection', :locals => { :categories => categories, :level => level }),
73   - :class => 'categories_container',
74   - :id => "categories_container_level#{ level }"
75   - )
76   - end
77   -
78   - def categories_container(categories_selection_html, hierarchy_html = '')
79   - content_tag 'div',
80   - safe_join(
81   - [
82   - render('categories_autocomplete'),
83   - hidden_field_tag('selected_category_id'),
84   - content_tag('div', hierarchy_html, :id => 'hierarchy_navigation'),
85   - content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
86   - ], ''),
87   - :id => 'categories-container'
88   - end
89   -
90   - def select_for_categories(categories, level = 0)
91   - if categories.empty?
92   - content_tag('div', '', :id => 'no_subcategories')
93   - else
94   - select_tag('category_id',
95   - options_for_select_categories(categories),
96   - :size => 10,
97   - :onchange => remote_function_to_update_categories_selection("categories_container_level#{ level + 1 }", :with => "'category_id=' + this.value")
98   - ) +
99   - content_tag('div', '', :class => 'categories_container', :id => "categories_container_level#{ level + 1 }")
100   - end
101   - end
102   -
103   - def edit_link(label, url, html_options = {})
104   - return '' unless (user && user.has_permission?('manage_products', profile))
105   - link_to(label, url, html_options)
106   - end
107   -
108   - def edit_product_link_to_remote(product, field, label, html_options = {})
109   - return '' unless (user && user.has_permission?('manage_products', profile))
110   - options = html_options.merge(:id => 'link-edit-product-' + field)
111   - options[:class] = options[:class] ? options[:class] + ' link-to-remote' : 'link-to-remote'
112   -
113   - link_to_remote(label,
114   - {:update => "product-#{field}",
115   - :url => { :controller => 'manage_products', :action => "edit", :id => product.id, :field => field },
116   - :method => :get,
117   - :loading => "loading_for_button('#link-edit-product-#{field}')"},
118   - options)
119   - end
120   -
121   - def edit_button(type, label, url, html_options = {})
122   - return '' unless (user && user.has_permission?('manage_products', profile))
123   - button(type, label, url, html_options)
124   - end
125   -
126   - def edit_product_button_to_remote(product, field, label, html_options = {})
127   - the_class = 'button with-text icon-edit'
128   - if html_options.has_key?(:class)
129   - the_class << ' ' << html_options[:class]
130   - end
131   - edit_product_link_to_remote(product, field, label, html_options.merge(:class => the_class))
132   - end
133   -
134   - def edit_ui_button(label, url, html_options = {})
135   - return '' unless (user && user.has_permission?('manage_products', profile))
136   - ui_button(label, url, html_options)
137   - end
138   -
139   - def edit_product_ui_button_to_remote(product, field, label, html_options = {})
140   - return '' unless (user && user.has_permission?('manage_products', profile))
141   - id = 'edit-product-remote-button-ui-' + field
142   - options = html_options.merge(:id => id)
143   -
144   - ui_button_to_remote(label,
145   - {:update => "product-#{field}",
146   - :url => { :controller => 'manage_products', :action => "edit", :id => product.id, :field => field },
147   - :complete => "jQuery('#edit-product-button-ui-#{field}').hide()",
148   - :method => :get,
149   - :loading => "loading_for_button('##{id}')"},
150   - options)
151   - end
152   -
153   - def cancel_edit_product_link(product, field, html_options = {})
154   - return '' unless (user && user.has_permission?('manage_products', profile))
155   - button_to_function(:cancel, _('Cancel'), nil, html_options) do |page|
156   - page.replace_html "product-#{field}", CGI::escapeHTML(render :partial => "display_#{field}", :locals => {:product => product})
157   - end
158   - end
159   -
160   - def edit_product_category_link(product, html_options = {})
161   - return '' unless (user && user.has_permission?('manage_products', profile))
162   - options = html_options.merge(:id => 'link-edit-product-category')
163   - link_to(_('Change category'), { :action => 'edit_category', :id => product.id}, options)
164   - end
165   -
166   - def display_value(product)
167   - price = product.price
168   - return '' if price.blank? || price.zero?
169   - discount = product.discount
170   - if discount.blank? || discount.zero?
171   - result = display_price(_('Price: '), price)
172   - else
173   - result = display_price_with_discount(price, product.price_with_discount)
174   - end
175   - content_tag('span', content_tag('span', result, :class => 'product-price'), :class => "#{product.available? ? '' : 'un'}available-product")
176   - end
177   -
178   - def display_availability(product)
179   - if !product.available?
180   - ui_highlight(_('Product not available!'))
181   - end
182   - end
183   -
184   - def display_price(label, price)
185   - content_tag('span', label, :class => 'field-name') +
186   - content_tag('span', float_to_currency(price), :class => 'field-value')
187   - end
188   -
189   - def display_price_with_discount(price, price_with_discount)
190   - original_value = content_tag('span', display_price(_('List price: '), price), :class => 'list-price')
191   - discount_value = content_tag('span', display_price(_('On sale: '), price_with_discount), :class => 'on-sale-price')
192   - original_value + tag('br') + discount_value
193   - end
194   -
195   - def display_qualifiers(product)
196   - data = ''
197   - product.product_qualifiers.each do |pq|
198   - certified_by = ''
199   - certifier = pq.certifier
200   - if certifier
201   - certifier_name = certifier.link.blank? ? certifier.name : link_to(certifier.name, certifier.link)
202   - certified_by = _('certified by %s') % certifier_name
203   - else
204   - certified_by = _('(Self declared)')
205   - end
206   - data << content_tag('li', "✔ #{pq.qualifier.name} #{certified_by}", :class => 'product-qualifiers-item')
207   - end
208   - content_tag('ul', data, :id => 'product-qualifiers')
209   - end
210   -
211   - def qualifiers_for_select
212   - [[_('Select...'), nil]] + environment.qualifiers.sort.map{ |c| [c.name, c.id] }
213   - end
214   - def certifiers_for_select(qualifier)
215   - [[_('Self declared'), nil]] + qualifier.certifiers.sort.map{ |c| [c.name, c.id] }
216   - end
217   - def select_qualifiers(product, selected = nil)
218   - select_tag('selected_qualifier', options_for_select(qualifiers_for_select, selected),
219   - :onchange => remote_function(
220   - :url => {:action => 'certifiers_for_selection'},
221   - :with => "'id=' + value + '&certifier_area=' + jQuery(this).parent().next().attr('id')",
222   - :before => "small_loading(jQuery(this).parent().next().attr('id'), '&nbsp;')"
223   - ),
224   - :id => nil
225   - )
226   - end
227   - def select_certifiers(qualifier, product = nil)
228   - if qualifier
229   - selected = product ? product.product_qualifiers.find_by(qualifier_id: qualifier.id).certifier_id : nil
230   - select_tag("product[qualifiers_list][#{qualifier.id}]", options_for_select(certifiers_for_select(qualifier), selected))
231   - else
232   - select_tag("product[qualifiers_list][nil]")
233   - end
234   - end
235   -
236   - def remove_qualifier_button
237   - button_to_function(:delete, content_tag('span', _('Delete qualifier')), "jQuery(this).parents('tr').remove()")
238   - end
239   -
240   - def select_unit(object)
241   - collection_select(object.class.name.downcase, :unit_id, environment.units, :id, :singular, {:include_blank => _('Select the unit')})
242   - end
243   -
244   - def input_icon(input)
245   - if input.is_from_solidarity_economy?
246   - hint = _('Product from solidarity economy')
247   - image_tag("/images/solidarity-economy.png", :class => 'solidatiry-economy-icon', :alt => hint, :title => hint)
248   - end
249   - end
250   -
251   - def display_price_by(unit)
252   - selected_unit = content_tag('span', unit, :class => 'selected-unit')
253   - content_tag('span', _('by') + ' ' + selected_unit, :class => 'price-by-unit')
254   - end
255   -
256   - def label_amount_used(input)
257   - product_unit = input.product.unit
258   - if product_unit.blank?
259   - _('Amount used in this product or service')
260   - else
261   - _('Amount used by %s of this product or service') % product_unit.singular.downcase
262   - end
263   - end
264   -
265   - def display_unit(input)
266   - input_amount_used = content_tag('span', input.formatted_amount, :class => 'input-amount-used')
267   - return input_amount_used if input.unit.blank?
268   - 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') }
269   - end
270   -
271   - def select_production_cost(product,selected=nil)
272   - url = url_for( :controller => 'manage_products', :action => 'create_production_cost' )
273   - prompt_msg = _('Insert the name of the new cost:')
274   - error_msg = _('Something went wrong. Please, try again')
275   - select_tag('price_details[][production_cost_id]',
276   - '<option value="" disabled="disabled">' + _('Select...') + '</option>' +
277   - options_for_select(product.available_production_costs.map {|item| [truncate(item.name, {:length => 10, :omission => '...'}), item.id]} + [[_('Other cost'), '']], selected),
278   - {:class => 'production-cost-selection',
279   - :onchange => "productionCostTypeChange(this, '#{url}', '#{prompt_msg}', '#{error_msg}')"})
280   - end
281   -
282   - def price_composition_progressbar_text(product, args = {})
283   - currency = environment.currency_unit
284   - production_cost = args[:production_cost_value] || product.formatted_value(:total_production_cost)
285   - product_price = args[:product_price] || product.formatted_value(:price)
286   -
287   - _("%{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')}
288   - end
289   -end
app/helpers/profile_image_helper.rb
... ... @@ -82,7 +82,6 @@ module ProfileImageHelper
82 82 ]
83 83 elsif profile.kind_of?(Enterprise)
84 84 [
85   - {_('Products') => {:href => catalog_path(profile.identifier)}},
86 85 {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}},
87 86 {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}},
88 87 {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}},
... ...
app/models/article.rb
... ... @@ -604,7 +604,7 @@ class Article &lt; ApplicationRecord
604 604 end
605 605  
606 606 def accept_category?(cat)
607   - !cat.is_a?(ProductCategory)
  607 + true
608 608 end
609 609  
610 610 def public?
... ...
app/models/box.rb
... ... @@ -41,7 +41,6 @@ class Box &lt; ApplicationRecord
41 41 ProfileImageBlock,
42 42 RawHTMLBlock,
43 43 RecentDocumentsBlock,
44   - SellersSearchBlock,
45 44 TagsBlock ]
46 45 end
47 46  
... ... @@ -54,21 +53,17 @@ class Box &lt; ApplicationRecord
54 53 EnterprisesBlock,
55 54 FansBlock,
56 55 FavoriteEnterprisesBlock,
57   - FeaturedProductsBlock,
58 56 FeedReaderBlock,
59 57 HighlightsBlock,
60 58 LinkListBlock,
61 59 LocationBlock,
62 60 LoginBlock,
63 61 MyNetworkBlock,
64   - ProductsBlock,
65   - ProductCategoriesBlock,
66 62 ProfileImageBlock,
67 63 ProfileInfoBlock,
68 64 ProfileSearchBlock,
69 65 RawHTMLBlock,
70 66 RecentDocumentsBlock,
71   - SellersSearchBlock,
72 67 SlideshowBlock,
73 68 TagsBlock
74 69 ]
... ...
app/models/category.rb
... ... @@ -35,8 +35,6 @@ class Category &lt; ApplicationRecord
35 35 has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person'
36 36 has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community'
37 37  
38   - has_many :products, :through => :enterprises
39   -
40 38 acts_as_having_image
41 39  
42 40 before_save :normalize_display_color
... ... @@ -64,10 +62,6 @@ class Category &lt; ApplicationRecord
64 62 self.communities.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit)
65 63 end
66 64  
67   - def recent_products(limit = 10)
68   - self.products.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit)
69   - end
70   -
71 65 def recent_articles(limit = 10)
72 66 self.articles.recent(limit)
73 67 end
... ...
app/models/certifier.rb
... ... @@ -1,35 +0,0 @@
1   -class Certifier < ApplicationRecord
2   -
3   - attr_accessible :name, :environment
4   -
5   - SEARCHABLE_FIELDS = {
6   - :name => {:label => _('Name'), :weight => 10},
7   - :description => {:label => _('Description'), :weight => 3},
8   - :link => {:label => _('Link'), :weight => 1},
9   - }
10   -
11   - belongs_to :environment
12   -
13   - has_many :qualifier_certifiers, :dependent => :destroy
14   - has_many :qualifiers, :through => :qualifier_certifiers
15   -
16   - has_many :product_qualifiers
17   - has_many :products, :through => :product_qualifiers, :source => :product
18   -
19   - validates_presence_of :environment_id
20   - validates_presence_of :name
21   -
22   - def destroy
23   - product_qualifiers.each { |pq| pq.update! :certifier => nil }
24   - super
25   - end
26   -
27   - def link
28   - self[:link] || ''
29   - end
30   -
31   - def <=>(b)
32   - self.name.downcase.transliterate <=> b.name.downcase.transliterate
33   - end
34   -
35   -end
app/models/enterprise.rb
1   -# An enterprise is a kind of organization. According to the system concept,
2   -# only enterprises can offer products and services.
3 1 class Enterprise < Organization
4 2  
5   - attr_accessible :business_name, :address_reference, :district, :tag_list, :organization_website, :historic_and_current_context, :activities_short_description, :products_per_catalog_page
  3 + attr_accessible :business_name, :address_reference, :district, :tag_list,
  4 + :organization_website, :historic_and_current_context, :activities_short_description
6 5  
7 6 SEARCH_FILTERS = {
8 7 :order => %w[more_recent more_popular more_active],
... ... @@ -17,11 +16,6 @@ class Enterprise &lt; Organization
17 16  
18 17 acts_as_trackable after_add: proc{ |p, t| notify_activity t }
19 18  
20   - has_many :products, :foreign_key => :profile_id, :dependent => :destroy
21   - has_many :product_categories, :through => :products
22   - has_many :inputs, :through => :products
23   - has_many :production_costs, :as => :owner
24   -
25 19 has_many :favorite_enterprise_people
26 20 has_many :fans, source: :person, through: :favorite_enterprise_people
27 21  
... ... @@ -29,10 +23,6 @@ class Enterprise &lt; Organization
29 23  
30 24 settings_items :organization_website, :historic_and_current_context, :activities_short_description
31 25  
32   - settings_items :products_per_catalog_page, :type => :integer, :default => 6
33   - alias_method :products_per_catalog_page_before_type_cast, :products_per_catalog_page
34   - validates_numericality_of :products_per_catalog_page, :allow_nil => true, :greater_than => 0
35   -
36 26 extend SetProfileRegionFromCityState::ClassMethods
37 27 set_profile_region_from_city_state
38 28  
... ... @@ -66,10 +56,6 @@ class Enterprise &lt; Organization
66 56 environment ? environment.active_enterprise_fields : []
67 57 end
68 58  
69   - def highlighted_products_with_image(options = {})
70   - Product.where(:highlighted => true).joins(:image)
71   - end
72   -
73 59 def required_fields
74 60 environment ? environment.required_enterprise_fields : []
75 61 end
... ... @@ -136,19 +122,14 @@ class Enterprise &lt; Organization
136 122 links = [
137 123 {:name => _("Enterprises's profile"), :address => '/profile/{profile}', :icon => 'ok'},
138 124 {:name => _('Blog'), :address => '/{profile}/blog', :icon => 'edit'},
139   - {:name => _('Products'), :address => '/catalog/{profile}', :icon => 'new'},
140 125 ]
141 126 blocks = [
142 127 [MainBlock.new],
143 128 [ ProfileImageBlock.new,
144 129 LinkListBlock.new(:links => links),
145   - ProductCategoriesBlock.new
146 130 ],
147 131 [LocationBlock.new]
148 132 ]
149   - if environment.enabled?('products_for_enterprises')
150   - blocks[2].unshift ProductsBlock.new
151   - end
152 133 blocks
153 134 end
154 135  
... ... @@ -189,14 +170,6 @@ class Enterprise &lt; Organization
189 170 {:title => _('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
190 171 end
191 172  
192   - def create_product?
193   - true
194   - end
195   -
196   - def catalog_url
197   - { :profile => identifier, :controller => 'catalog'}
198   - end
199   -
200 173 def more_recent_label
201 174 ''
202 175 end
... ... @@ -205,5 +178,4 @@ class Enterprise &lt; Organization
205 178 super or self.fans.where(id: person.id).count > 0
206 179 end
207 180  
208   -
209 181 end
... ...
app/models/enterprise_homepage.rb
... ... @@ -1,42 +0,0 @@
1   -class EnterpriseHomepage < Article
2   -
3   - def self.type_name
4   - _('Homepage')
5   - end
6   -
7   - def self.short_description
8   - _('Enterprise homepage')
9   - end
10   -
11   - def self.description
12   - _('Display the summary of profile.')
13   - end
14   -
15   - def name
16   - profile.nil? ? _('Homepage') : profile.name
17   - end
18   -
19   - def to_html(options = {})
20   - enterprise_homepage = self
21   - proc do
22   - extend EnterpriseHomepageHelper
23   - extend CatalogHelper
24   - catalog_load_index :page => 1, :show_categories => false
25   - render :partial => 'content_viewer/enterprise_homepage', :object => enterprise_homepage
26   - end
27   - end
28   -
29   - # disable cache because of products
30   - def cache_key params = {}, the_profile = nil, language = 'en'
31   - rand
32   - end
33   -
34   - def can_display_hits?
35   - false
36   - end
37   -
38   - def can_display_media_panel?
39   - true
40   - end
41   -
42   -end
app/models/environment.rb
... ... @@ -128,7 +128,6 @@ class Environment &lt; ApplicationRecord
128 128 'disable_asset_enterprises' => _('Disable search for enterprises'),
129 129 'disable_asset_people' => _('Disable search for people'),
130 130 'disable_asset_communities' => _('Disable search for communities'),
131   - 'disable_asset_products' => _('Disable search for products'),
132 131 'disable_asset_events' => _('Disable search for events'),
133 132 'disable_categories' => _('Disable categories'),
134 133 'disable_header_and_footer' => _('Disable header/footer editing by users'),
... ... @@ -139,7 +138,6 @@ class Environment &lt; ApplicationRecord
139 138 'disable_contact_community' => _('Disable contact for groups/communities'),
140 139 'forbid_destroy_profile' => _('Forbid users of removing profiles'),
141 140  
142   - 'products_for_enterprises' => _('Enable products for enterprises'),
143 141 'enterprise_registration' => _('Enterprise registration'),
144 142 'enterprise_activation' => _('Enable activation of enterprises'),
145 143 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'),
... ... @@ -226,7 +224,6 @@ class Environment &lt; ApplicationRecord
226 224  
227 225 has_many :organizations
228 226 has_many :enterprises
229   - has_many :products, :through => :enterprises
230 227 has_many :people
231 228 has_many :communities
232 229 has_many :licenses
... ... @@ -236,23 +233,16 @@ class Environment &lt; ApplicationRecord
236 233 order('display_color').where('display_color is not null and parent_id is null')
237 234 }, class_name: 'Category'
238 235  
239   - has_many :product_categories, -> { where type: 'ProductCategory'}
240 236 has_many :regions
241 237 has_many :states
242 238 has_many :cities
243 239  
244 240 has_many :roles, :dependent => :destroy
245 241  
246   - has_many :qualifiers
247   - has_many :certifiers
248   -
249 242 has_many :mailings, :class_name => 'EnvironmentMailing', :foreign_key => :source_id, :as => 'source'
250 243  
251 244 acts_as_accessible
252 245  
253   - has_many :units, -> { order 'position' }
254   - has_many :production_costs, :as => :owner
255   -
256 246 def superior_intances
257 247 [self, nil]
258 248 end
... ... @@ -441,9 +431,7 @@ class Environment &lt; ApplicationRecord
441 431 end
442 432  
443 433 DEFAULT_FEATURES = %w(
444   - disable_asset_products
445 434 disable_gender_icon
446   - products_for_enterprises
447 435 disable_select_city_for_contact
448 436 enterprise_registration
449 437 media_panel
... ... @@ -968,10 +956,6 @@ class Environment &lt; ApplicationRecord
968 956 end
969 957 end
970 958  
971   - def highlighted_products_with_image(options = {})
972   - self.products.where(highlighted: true).joins(:image).order('created_at ASC')
973   - end
974   -
975 959 settings_items :home_cache_in_minutes, :type => :integer, :default => 5
976 960 settings_items :general_cache_in_minutes, :type => :integer, :default => 15
977 961 settings_items :profile_cache_in_minutes, :type => :integer, :default => 15
... ...
app/models/featured_products_block.rb
... ... @@ -1,35 +0,0 @@
1   -class FeaturedProductsBlock < Block
2   -
3   - attr_accessible :product_ids, :groups_of, :speed, :reflect
4   -
5   - settings_items :product_ids, :type => Array, :default => []
6   - settings_items :groups_of, :type => :integer, :default => 3
7   - settings_items :speed, :type => :integer, :default => 1000
8   - settings_items :reflect, :type => :boolean, :default => true
9   -
10   - before_save do |block|
11   - if block.owner.kind_of?(Environment) && block.product_ids.blank?
12   - total = block.owner.products.count
13   - offset = rand([(total - block.groups_of * 3) + 1, 1].max)
14   - block.product_ids = block.owner.highlighted_products_with_image.offset(offset).limit(block.groups_of * 3).map(&:id)
15   - end
16   - block.groups_of = block.groups_of.to_i
17   - end
18   -
19   - def self.description
20   - _('Featured Products')
21   - end
22   -
23   - def self.pretty_name
24   - _('Featured Products')
25   - end
26   -
27   - def products
28   - Product.find(self.product_ids) || []
29   - end
30   -
31   - def products_for_selection
32   - self.owner.highlighted_products_with_image
33   - end
34   -
35   -end
app/models/input.rb
... ... @@ -1,71 +0,0 @@
1   -class Input < ApplicationRecord
2   -
3   - attr_accessible :product, :product_id, :product_category, :product_category_id,
4   - :amount_used, :unit_id, :price_per_unit, :relevant_to_price, :is_from_solidarity_economy
5   -
6   - belongs_to :product
7   - belongs_to :product_category
8   -
9   - validates_presence_of :product
10   - validates_presence_of :product_category
11   -
12   - acts_as_list scope: -> input { where product_id: input.product_id }
13   -
14   - belongs_to :unit
15   -
16   - scope :relevant_to_price, -> { where relevant_to_price: true }
17   -
18   - include FloatHelper
19   -
20   - def price_per_unit=(value)
21   - if value.is_a?(String)
22   - super(decimal_to_float(value))
23   - else
24   - super(value)
25   - end
26   - end
27   -
28   - def amount_used=(value)
29   - if value.is_a?(String)
30   - super(decimal_to_float(value))
31   - else
32   - super(value)
33   - end
34   - end
35   -
36   - def name
37   - product_category.name
38   - end
39   -
40   - def formatted_value(value)
41   - ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value]
42   - end
43   -
44   - def formatted_amount
45   - amount = self.amount_used
46   - return '' if amount.blank? || amount.zero?
47   - ("%.2f" % amount).to_s.gsub('.00', '').gsub('.', product.enterprise.environment.currency_separator)
48   - end
49   -
50   - def has_price_details?
51   - %w[price_per_unit amount_used].each do |field|
52   - return true unless self.send(field).blank?
53   - end
54   - false
55   - end
56   -
57   - def has_all_price_details?
58   - %w[price_per_unit unit amount_used].each do |field|
59   - return false if self.send(field).blank?
60   - end
61   - true
62   - end
63   -
64   - def cost
65   - return 0 if self.amount_used.blank? || self.price_per_unit.blank?
66   - self.amount_used * self.price_per_unit
67   - end
68   -
69   - alias_method :price, :cost
70   -
71   -end
app/models/price_detail.rb
... ... @@ -1,33 +0,0 @@
1   -class PriceDetail < ApplicationRecord
2   -
3   - attr_accessible :price, :production_cost_id
4   -
5   - belongs_to :product
6   - validates_presence_of :product_id
7   -
8   - belongs_to :production_cost
9   - # Do not validates_presence_of production_cost. We may have undefined other costs.
10   - validates_uniqueness_of :production_cost_id, :scope => :product_id
11   -
12   - def name
13   - production_cost.nil? ? _('Other costs') : production_cost.name
14   - end
15   -
16   - def price
17   - self[:price] || 0
18   - end
19   -
20   - include FloatHelper
21   - def price=(value)
22   - if value.is_a?(String)
23   - super(decimal_to_float(value))
24   - else
25   - super(value)
26   - end
27   - end
28   -
29   - def formatted_value(value)
30   - ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value]
31   - end
32   -
33   -end
app/models/product.rb
... ... @@ -1,291 +0,0 @@
1   -class Product < ApplicationRecord
2   -
3   - SEARCHABLE_FIELDS = {
4   - :name => {:label => _('Name'), :weight => 10},
5   - :description => {:label => _('Description'), :weight => 1},
6   - }
7   -
8   - SEARCH_FILTERS = {
9   - :order => %w[more_recent],
10   - :display => %w[full map]
11   - }
12   -
13   - attr_accessible :name, :product_category, :profile, :profile_id, :enterprise,
14   - :highlighted, :price, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
15   -
16   - def self.default_search_display
17   - 'full'
18   - end
19   -
20   - belongs_to :profile
21   - # backwards compatibility
22   - belongs_to :enterprise, :foreign_key => :profile_id, :class_name => 'Profile'
23   - alias_method :enterprise=, :profile=
24   - alias_method :enterprise, :profile
25   -
26   - has_one :region, :through => :profile
27   - validates_presence_of :profile
28   -
29   - belongs_to :product_category
30   -
31   - has_many :inputs, -> { order 'position' }, dependent: :destroy
32   - has_many :price_details, :dependent => :destroy
33   - has_many :production_costs, :through => :price_details
34   -
35   - has_many :product_qualifiers, :dependent => :destroy
36   - has_many :qualifiers, :through => :product_qualifiers
37   - has_many :certifiers, :through => :product_qualifiers
38   -
39   - acts_as_having_settings :field => :data
40   -
41   - track_actions :create_product, :after_create, :keep_params => [:name, :url ], :if => Proc.new { |a| a.is_trackable? }, :custom_user => :action_tracker_user
42   - track_actions :update_product, :before_update, :keep_params => [:name, :url], :if => Proc.new { |a| a.is_trackable? }, :custom_user => :action_tracker_user
43   - track_actions :remove_product, :before_destroy, :keep_params => [:name], :if => Proc.new { |a| a.is_trackable? }, :custom_user => :action_tracker_user
44   -
45   - validates_uniqueness_of :name, :scope => :profile_id, :allow_nil => true, :if => :validate_uniqueness_of_column_name?
46   -
47   - validates_presence_of :product_category_id
48   - validates_associated :product_category
49   -
50   - validates_numericality_of :price, :allow_nil => true
51   - validates_numericality_of :discount, :allow_nil => true
52   -
53   - scope :more_recent, -> { order 'created_at DESC' }
54   -
55   - scope :from_category, -> category {
56   - joins(:product_category).where('categories.path LIKE ?', "%#{category.slug}%") if category
57   - }
58   -
59   - scope :visible_for_person, lambda { |person|
60   - joins('INNER JOIN "profiles" enterprises ON enterprises."id" = "products"."profile_id"')
61   - .joins('LEFT JOIN "role_assignments" ON ("role_assignments"."resource_id" = enterprises."id"
62   - AND "role_assignments"."resource_type" = \'Profile\') OR (
63   - "role_assignments"."resource_id" = enterprises."environment_id" AND
64   - "role_assignments"."resource_type" = \'Environment\' )')
65   - .joins('LEFT JOIN "roles" ON "role_assignments"."role_id" = "roles"."id"')
66   - .where(
67   - ['( (roles.key = ? OR roles.key = ?) AND role_assignments.accessor_type = \'Profile\' AND role_assignments.accessor_id = ? )
68   - OR
69   - ( ( ( role_assignments.accessor_type = \'Profile\' AND
70   - role_assignments.accessor_id = ? ) OR
71   - ( enterprises.public_profile = ? AND enterprises.enabled = ? ) ) AND
72   - ( enterprises.visible = ? ) )',
73   - 'profile_admin', 'environment_administrator', person.id, person.id,
74   - true, true, true]
75   - ).uniq
76   - }
77   -
78   - scope :recent, -> limit=nil { order('id DESC').limit(limit) }
79   -
80   - after_update :save_image
81   -
82   - def lat
83   - self.profile.lat
84   - end
85   - def lng
86   - self.profile.lng
87   - end
88   -
89   - xss_terminate :only => [ :name ], :on => 'validation'
90   - xss_terminate :only => [ :description ], :with => 'white_list', :on => 'validation'
91   -
92   - belongs_to :unit
93   -
94   - include FloatHelper
95   -
96   - include WhiteListFilter
97   - filter_iframes :description
98   -
99   - def iframe_whitelist
100   - self.profile && self.profile.environment && self.profile.environment.trusted_sites_for_iframe
101   - end
102   -
103   - def name
104   - self[:name].blank? ? category_name : self[:name]
105   - end
106   -
107   - def name=(value)
108   - if (value == category_name)
109   - self[:name] = nil
110   - else
111   - self[:name] = value
112   - end
113   - end
114   -
115   - def name_is_blank?
116   - self[:name].blank?
117   - end
118   -
119   - def default_image(size='thumb')
120   - image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size
121   - end
122   -
123   - acts_as_having_image
124   -
125   - def save_image
126   - image.save if image
127   - end
128   -
129   - def category_name
130   - product_category ? product_category.name : _('Uncategorized product')
131   - end
132   -
133   - def url
134   - self.profile.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => id)
135   - end
136   -
137   - def public?
138   - self.profile.public?
139   - end
140   -
141   - def formatted_value(method)
142   - value = self[method] || self.send(method)
143   - ("%.2f" % value).to_s.gsub('.', self.profile.environment.currency_separator) if value
144   - end
145   -
146   - def price_with_discount
147   - discount ? (price - discount) : price
148   - end
149   -
150   - def price=(value)
151   - if value.is_a?(String)
152   - super(decimal_to_float(value))
153   - else
154   - super(value)
155   - end
156   - end
157   -
158   - def discount=(value)
159   - if value.is_a?(String)
160   - super(decimal_to_float(value))
161   - else
162   - super(value)
163   - end
164   - end
165   -
166   - def inputs_prices?
167   - return false if self.inputs.count <= 0
168   - self.inputs.each do |input|
169   - return false if input.has_price_details? == false
170   - end
171   - true
172   - end
173   -
174   - def any_inputs_details?
175   - return false if self.inputs.count <= 0
176   - self.inputs.each do |input|
177   - return true if input.has_all_price_details? == true
178   - end
179   - false
180   - end
181   -
182   - def has_basic_info?
183   - %w[unit price discount].each do |field|
184   - return true if !self.send(field).blank?
185   - end
186   - false
187   - end
188   -
189   - def qualifiers_list=(qualifiers)
190   - self.product_qualifiers.destroy_all
191   - qualifiers.each do |qualifier_id, certifier_id|
192   - if qualifier_id != 'nil'
193   - product_qualifier = ProductQualifier.new
194   - product_qualifier.product = self
195   - product_qualifier.qualifier_id = qualifier_id
196   - product_qualifier.certifier_id = certifier_id
197   - product_qualifier.save!
198   - end
199   - end
200   - end
201   -
202   - def order_inputs!(order = [])
203   - order.each_with_index do |input_id, array_index|
204   - input = self.inputs.find(input_id)
205   - input.position = array_index + 1
206   - input.save!
207   - end
208   - end
209   -
210   - def name_with_unit
211   - unit.blank? ? name : "#{name} - #{unit.name.downcase}"
212   - end
213   -
214   - def display_supplier_on_search?
215   - true
216   - end
217   -
218   - def inputs_cost
219   - return 0 if inputs.empty?
220   - inputs.relevant_to_price.map(&:cost).inject { |sum,price| sum + price }
221   - end
222   -
223   - def total_production_cost
224   - return inputs_cost if price_details.empty?
225   - inputs_cost + price_details.map(&:price).inject(0){ |sum,price| sum + price }
226   - end
227   -
228   - def price_described?
229   - return false if price.blank? or price == 0
230   - (price - total_production_cost.to_f).zero?
231   - end
232   -
233   - def update_price_details(new_price_details)
234   - price_details.destroy_all
235   - new_price_details.each do |detail|
236   - price_details.create(detail)
237   - end
238   - reload # to remove temporary duplicated price_details
239   - price_details
240   - end
241   -
242   - def price_description_percentage
243   - return 0 if price.blank? || price.zero?
244   - total_production_cost * 100 / price
245   - end
246   -
247   - def available_production_costs
248   - self.profile.environment.production_costs + self.profile.production_costs
249   - end
250   -
251   - include Rails.application.routes.url_helpers
252   - def price_composition_bar_display_url
253   - url_for({:host => self.profile.default_hostname, :controller => 'manage_products', :action => 'display_price_composition_bar', :profile => self.profile.identifier, :id => self.id }.merge(Noosfero.url_options))
254   - end
255   -
256   - def inputs_cost_update_url
257   - url_for({:host => self.profile.default_hostname, :controller => 'manage_products', :action => 'display_inputs_cost', :profile => self.profile.identifier, :id => self.id }.merge(Noosfero.url_options))
258   - end
259   -
260   - def percentage_from_solidarity_economy
261   - se_i = t_i = 0
262   - self.inputs.each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
263   - t_i = 1 if t_i == 0 # avoid division by 0
264   - p = case (se_i.to_f/t_i)*100
265   - when 0 then [0, '']
266   - when 0..24.999 then [0, _("0%")];
267   - when 25..49.999 then [25, _("25%")];
268   - when 50..74.999 then [50, _("50%")];
269   - when 75..99.999 then [75, _("75%")];
270   - when 100 then [100, _("100%")];
271   - end
272   - end
273   -
274   - delegate :enabled, :region, :region_id, :environment, :environment_id, :to => :profile, allow_nil: true
275   -
276   - protected
277   -
278   - def validate_uniqueness_of_column_name?
279   - true
280   - end
281   -
282   - def is_trackable?
283   - # shopping_cart create products without profile
284   - self.profile.present?
285   - end
286   -
287   - def action_tracker_user
288   - self.profile
289   - end
290   -
291   -end
app/models/product_categories_block.rb
... ... @@ -1,30 +0,0 @@
1   -class ProductCategoriesBlock < Block
2   -
3   - def self.description
4   - _('Product category menu')
5   - end
6   -
7   - # the title of the block. Probably will be overriden in subclasses.
8   - def default_title
9   - _('Catalog')
10   - end
11   -
12   - def help
13   - _('Helps to filter the products catalog.')
14   - end
15   -
16   - DISPLAY_OPTIONS = DISPLAY_OPTIONS.merge('catalog_only' => _('Only on the catalog'))
17   -
18   - def display
19   - settings[:display].nil? ? 'catalog_only' : super
20   - end
21   -
22   - def display_catalog_only(context)
23   - context[:params][:controller] == 'catalog'
24   - end
25   -
26   - def visible?(*args)
27   - box.environment.enabled?('products_for_enterprises') ? super(*args) : false
28   - end
29   -
30   -end
app/models/product_category.rb
... ... @@ -1,29 +0,0 @@
1   -class ProductCategory < Category
2   - # FIXME: do not allow category with products or inputs to be destroyed
3   - has_many :products
4   - has_many :inputs
5   -
6   - attr_accessible :name, :parent, :environment
7   -
8   - scope :unique, -> { select 'DISTINCT ON (path) categories.*' }
9   - scope :by_enterprise, -> enterprise {
10   - distinct.joins(:products).
11   - where('products.profile_id = ?', enterprise.id)
12   - }
13   - scope :by_environment, -> environment {
14   - where 'environment_id = ?', environment.id
15   - }
16   -
17   - scope :unique_by_level, lambda { |level| {
18   - :select => "DISTINCT ON (filtered_category) split_part(path, '/', #{level.to_i}) AS filtered_category, categories.*"
19   - }}
20   -
21   - def all_products
22   - Product.where(product_category_id: (all_children << self).map(&:id))
23   - end
24   -
25   - def self.menu_categories(top_category, env)
26   - top_category ? top_category.children : top_level_for(env).select{|c|c.kind_of?(ProductCategory)}
27   - end
28   -
29   -end
app/models/product_qualifier.rb
... ... @@ -1,8 +0,0 @@
1   -class ProductQualifier < ApplicationRecord
2   -
3   - attr_accessible :qualifier, :product, :certifier
4   -
5   - belongs_to :qualifier
6   - belongs_to :product
7   - belongs_to :certifier
8   -end
app/models/production_cost.rb
... ... @@ -1,11 +0,0 @@
1   -class ProductionCost < ApplicationRecord
2   -
3   - attr_accessible :name, :owner
4   -
5   - belongs_to :owner, :polymorphic => true
6   - validates_presence_of :owner
7   - validates_presence_of :name
8   - validates_length_of :name, :maximum => 30, :allow_blank => true
9   - validates_uniqueness_of :name, :scope => [:owner_id, :owner_type]
10   -
11   -end
app/models/products_block.rb
... ... @@ -1,38 +0,0 @@
1   -class ProductsBlock < Block
2   -
3   - attr_accessible :product_ids
4   -
5   - include ActionView::Helpers::TagHelper
6   - include ActionView::Helpers::UrlHelper
7   - include ActionView::Helpers
8   - include Rails.application.routes.url_helpers
9   -
10   - def self.description
11   - _('Products')
12   - end
13   -
14   - def default_title
15   - _('Products')
16   - end
17   -
18   - def help
19   - _('This block presents a list of your products.')
20   - end
21   -
22   - settings_items :product_ids, type: Array
23   - def product_ids=(array)
24   - self.settings[:product_ids] = array
25   - if self.settings[:product_ids]
26   - self.settings[:product_ids] = self.settings[:product_ids].map(&:to_i)
27   - end
28   - end
29   -
30   - def products(reload = false)
31   - if product_ids.blank?
32   - owner.products.order('RANDOM()').limit([4,owner.products.count].min)
33   - else
34   - owner.products.where(:id => product_ids)
35   - end.compact
36   - end
37   -
38   -end
app/models/profile.rb
... ... @@ -812,7 +812,7 @@ private :generate_url, :url_options
812 812 end
813 813  
814 814 def accept_category?(cat)
815   - forbidden = [ ProductCategory, Region ]
  815 + forbidden = [ Region ]
816 816 !forbidden.include?(cat.class)
817 817 end
818 818  
... ...
app/models/qualifier.rb
... ... @@ -1,30 +0,0 @@
1   -class Qualifier < ApplicationRecord
2   -
3   - attr_accessible :name, :environment
4   -
5   - SEARCHABLE_FIELDS = {
6   - :name => {:label => _('Name'), :weight => 1},
7   - }
8   -
9   - belongs_to :environment
10   -
11   - has_many :qualifier_certifiers, :dependent => :destroy
12   - has_many :certifiers, :through => :qualifier_certifiers
13   -
14   - def used_certs
15   - Certifier.joins('INNER JOIN product_qualifiers' +
16   - ' ON certifiers.id = product_qualifiers.certifier_id')
17   - .where(product_qualifiers: {qualifier_id: self.id})
18   - end
19   -
20   - has_many :product_qualifiers, :dependent => :destroy
21   - has_many :products, :through => :product_qualifiers, :source => :product
22   -
23   - validates_presence_of :environment_id
24   - validates_presence_of :name
25   -
26   - def <=>(b)
27   - self.name.downcase.transliterate <=> b.name.downcase.transliterate
28   - end
29   -
30   -end
app/models/qualifier_certifier.rb
... ... @@ -1,6 +0,0 @@
1   -class QualifierCertifier < ApplicationRecord
2   - belongs_to :qualifier
3   - belongs_to :certifier
4   -
5   - validates_presence_of :qualifier
6   -end
app/models/sellers_search_block.rb
... ... @@ -1,25 +0,0 @@
1   -class SellersSearchBlock < Block
2   -
3   - attr_accessible :title
4   -
5   - def self.description
6   - _('Search for enterprises and products')
7   - end
8   -
9   - def self.short_description
10   - _('Products/Enterprises search')
11   - end
12   -
13   - def self.pretty_name
14   - _('Sellers Search')
15   - end
16   -
17   - def default_title
18   - _('Search for sellers')
19   - end
20   -
21   - def help
22   - _('This block presents a search engine for products.')
23   - end
24   -
25   -end
app/models/unit.rb
... ... @@ -1,23 +0,0 @@
1   -class Unit < ApplicationRecord
2   -
3   - acts_as_list scope: -> unit { where environment_id: unit.environment_id }
4   -
5   - attr_accessible :name, :singular, :plural, :environment
6   -
7   - validates_presence_of :singular
8   - validates_presence_of :plural
9   -
10   - belongs_to :environment
11   -
12   - validates_presence_of :environment_id
13   - validates_presence_of :singular
14   - validates_presence_of :plural
15   -
16   - def name
17   - self.singular
18   - end
19   - def name=(value)
20   - self.singular = value
21   - end
22   -
23   -end
app/views/blocks/footers/products.html.erb
... ... @@ -1 +0,0 @@
1   -<%= link_to(_('View all products'), block.owner.public_profile_url.merge(:controller => 'catalog', :action => 'index')) %>
app/views/blocks/product_categories.html.erb
... ... @@ -1,19 +0,0 @@
1   -<%
2   - if @categories.nil? or @categories.length == 0
3   - categories = ProductCategory.on_level(nil).order(:name)
4   - else
5   - categories = @categories
6   - end
7   -%>
8   -
9   -<%= link_to _('Catalog start'), block.owner.catalog_url, :class=>'catalog-home-link' %>
10   -<ul class="catalog-categories-list">
11   - <% categories.each do |category| %>
12   - <%= category_with_sub_list(category) %>
13   - <% end %>
14   -</ul>
15   -<% if @categories and @categories.length == 0 %>
16   - <div class="catalog-categories-notice">
17   - <%= _('There are no sub-categories for %s') % @category.name %>
18   - </div>
19   -<% end %>
app/views/blocks/products.html.erb
... ... @@ -1,9 +0,0 @@
1   -<%= block_title(block.title, block.subtitle) %>
2   -
3   -<ul>
4   - <% block.products.each do |product| %>
5   - <li class='product'>
6   - <%= link_to(product.name, product.url, :style => 'background-image:url(%s)' % product.default_image('minor')) %>
7   - </li>
8   - <% end %>
9   -</ul>
app/views/blocks/profile_info.html.erb
... ... @@ -16,9 +16,6 @@
16 16 <ul class="profile-info-data">
17 17 <li><%= link_to _('Homepage'), block.owner.url, :class => 'url' %></li>
18 18 <li><%= link_to _('View profile'), block.owner.public_profile_url %></li>
19   - <% if block.owner.enterprise? && block.owner.environment.enabled?('products_for_enterprises') %>
20   - <li><%= link_to(_('Products/Services'), :controller => 'catalog', :profile => block.owner.identifier) %></li>
21   - <% end %>
22 19 <% if !user.nil? and user.has_permission?('edit_profile', profile) %>
23 20 <li><%= link_to _('Control panel'), block.owner.admin_url %></li>
24 21 <% end %>
... ...
app/views/blocks/sellers_search.html.erb
... ... @@ -1,24 +0,0 @@
1   -<h3><%= block.title %></h3>
2   -
3   -<%= form_tag({:controller => 'search', :action => 'assets'}, {:method => 'get'}) do %>
4   -
5   - <div class="search-in-opt"><%= _('Search in:') %>
6   - <dir>
7   - <%= labelled_radio_button _('Enterprises'), 'asset', 'enterprises', true %><br />
8   - <%= labelled_radio_button _('Products'), 'asset', 'products', false %>
9   - </dir>
10   - </div>
11   -
12   - <div class="formfield search-from-opt">
13   - <%= select_city(true) %>
14   - </div>
15   -
16   - <div class="formfield search-distance-opt">
17   - <%= labelled_select(_('Distance:'), 'radius', :first, :last, nil, [15, 30, 50, 100, 150, 200, 300, 400, 500, 1000].map{|n|[n, n.to_s + 'km']}) %>
18   - </div>
19   -
20   - <div class="button-bar">
21   - <%= submit_button :search, _('Search') %>
22   - </div>
23   -
24   -<% end %>
app/views/box_organizer/_featured_products_block.html.erb
... ... @@ -1,8 +0,0 @@
1   -<strong><%= _('Featured Products') %></strong>
2   -<div id='edit-featured-products-block'>
3   - <p><%= label_tag _('Choose some products') %></p>
4   - <p><%= 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 %></p>
5   - <p><%= labelled_form_field check_box(:block, :reflect) + _('Reflect products'), '' %></p>
6   - <p><%= labelled_form_field(_('Transition speed (in seconds)'), select('block', 'speed', (1..10).to_a.collect{|i| [i, i*1000] })) %>
7   - <p><%= labelled_form_field(_('In groups of'), select('block', 'groups_of', (1..10).to_a)) %>
8   -</div>
app/views/box_organizer/_products_block.html.erb
... ... @@ -1,13 +0,0 @@
1   -<strong></strong>
2   -
3   -<p>
4   -<strong>
5   -<%= _('Select the products that must be shown.') %>
6   -</strong>
7   -</p>
8   -
9   -<% for product in @block.owner.products %>
10   - <%= check_box_tag("block[product_ids][]", product.id, (!@block.product_ids.blank? && @block.product_ids.include?(product.id)), :id => "block_product_ids_#{product.id}" ) %>
11   - <label for="block_product_ids_<%= product.id %>"><%= product.name %></label>
12   - <br/>
13   -<% end %>
app/views/box_organizer/edit.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %>
7 7 <%= labelled_form_field(_('Custom subtitle for this block: '), text_field(:block, :subtitle)) %>
8 8  
9   - <%= render :partial => partial_for_class(@block.class) %>
  9 + <%= render_partial_for_class @block.class %>
10 10  
11 11 <div class="display">
12 12 <%= labelled_form_field _('Display this block:'),
... ...
app/views/catalog/index.html.erb
... ... @@ -1,130 +0,0 @@
1   -<% extra_content = [] %>
2   -<% extra_content_list = [] %>
3   -
4   -<div id="product-catalog">
5   -<% if !user.nil? && ( user.is_admin?(profile.environment) || user.is_admin?(profile) ) %>
6   - <div class="product-catalog-ctrl">
7   - <%= button :product, _('Manage Products/Services'), :controller => 'manage_products' %>
8   - </div>
9   -<% end %>
10   -
11   -<h1><%= _('Products/Services') %></h1>
12   -
13   -<%= breadcrumb(@category) if params[:level] %>
14   -
15   -<ul id="product-list">
16   - <% @products.each do |product| %>
17   - <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_exec(&content) } %>
18   - <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_exec(&content) } %>
19   -
20   - <% status = [] %>
21   - <% status << 'not-available' if !product.available %>
22   - <% status << 'highlighted' if product.highlighted %>
23   -
24   - <li id="product-<%= product.id %>" class="product <%= status.join(' ') %>">
25   - <ul>
26   - <li class="product-image-link">
27   - <% if product.highlighted? %>
28   - <%= link_to image_tag(themed_path('/images/star.png'), :class => 'star', :alt => _('Highlighted product')), product_path(product) %>
29   - <% end %>
30   - <% if product.image %>
31   - <div class="zoomable-image">
32   - <%= link_to_product product, :class => 'product-big', :style => "background-image: url(#{product.default_image(:big)})" %>
33   - <%= link_to content_tag(:span, _('Zoom in')), product.default_image(:big).gsub('_big',''), :class => 'zoomify-image' %>
34   - </div>
35   - <% else %>
36   - <div class="no-image"><%= _('No image') %></div>
37   - <% end %>
38   - <div class="catalog-item-extras"><%= safe_join(extra_content, "\n") %></div>
39   - </li>
40   -
41   - <li class="product-link"><%= link_to_product product %></li>
42   -
43   - <li class="product-price-line">
44   - <% unless product.discount.blank? or product.discount == 0 %>
45   - <span class="product-discount">
46   - <span><%= _('from ') + price_span(product.price) %></span>
47   - <span class="product-discount-by"><%= _('by ') %></span>
48   - </span>
49   - <% end %>
50   - <% unless product.price.blank? or product.price == 0 %>
51   - <span class="product-price">
52   - <%= price_span product.price_with_discount, :class => "product-price #{'with-discount' unless product.discount}" %>
53   - <span class="product-unit"><%= _(' / ') + (product.unit ? product.unit.singular : _('unit')) %></span>
54   - </span>
55   - <% end %>
56   - <div style="clear: both"></div>
57   - </li>
58   -
59   - <% if product.description %>
60   - <li class="product-description expand-box">
61   - <span class="product-description-button"><%= _('description') %></span>
62   - <div class="float-box">
63   - <div class="arrow"></div>
64   - <div class="content"><%= product.description %></div>
65   - </div>
66   - </li>
67   - <% end %>
68   -
69   - <% if product.price_described? %>
70   - <li class="product-price-composition expand-box">
71   - <span class="product-price-composition-button"><%= _('price composition') %></span>
72   - <div class="float-box">
73   - <div class="arrow"></div>
74   - <div class="content">
75   - <% product.inputs.relevant_to_price.each do |i| %>
76   - <div class="search-product-input-dots-to-price">
77   - <div class="search-product-input-name"><%= i.product_category.name %></div>
78   - <%= price_span i.cost, :class => 'search-product-input-price' %>
79   - </div>
80   - <% end %>
81   - <% product.price_details.each do |i| %>
82   - <div class="search-product-input-dots-to-price">
83   - <div class="search-product-input-name"><%= i.name %></div>
84   - <%= price_span i.price, :class => 'search-product-input-price' %>
85   - </div>
86   - <% end %>
87   - </div>
88   - </div>
89   - </li>
90   - <% end %>
91   -
92   - <% if product.inputs.count > 0 %>
93   - <li class="product-inputs expand-box">
94   - <span id="inputs-button"><%= _('inputs and raw materials') %></span>
95   - <div class="float-box">
96   - <div class="arrow"></div>
97   - <div class="content">
98   - <% product.inputs.each do |i| %>
99   - <div>
100   - <%= _('%{amount_used} %{unit} of') % {:amount_used => i.amount_used, :unit => i.unit.singular} + ' ' if i.has_all_price_details? %>
101   - <%= i.product_category.name %>
102   - </div>
103   - <% end %>
104   - </div>
105   - </div>
106   - </li>
107   - <% end %>
108   -
109   - <% unless product.qualifiers.blank? %>
110   - <li class="product-qualifiers">
111   - <span><%= _('qualifiers') if product.product_qualifiers.count > 0 %></span>
112   - <div><%= render :partial => 'shared/product/qualifiers', :locals => {:product => product} %></div>
113   - <% end %>
114   -
115   - <% extra_content_list.map do |content| %>
116   - <li class="catalog-list-item-extras"><%= content %></li>
117   - <% end %>
118   -
119   - <li class="product-unavailable"><%= _('product unavailable') unless product.available %></li>
120   - </ul>
121   - </li>
122   - <% end %>
123   -</ul><!-- end id="product-list" -->
124   -
125   -<%= pagination_links @products, :params => {:controller => :catalog, :action => :index, :profile => profile.identifier} %>
126   -
127   -<%= add_zoom_to_images %>
128   -
129   -<br style="clear:both"/>
130   -</div><!-- end id="product-catalog" -->
app/views/categories/index.html.erb
... ... @@ -7,15 +7,6 @@
7 7 <%= link_to _('New category'), :action => 'new' %>
8 8 </div>
9 9  
10   -<h1><%= _('Product Categories') %></h1>
11   -<ul class='tree'>
12   - <%= render :partial => 'category', :collection => @product_categories %>
13   -</ul>
14   -
15   -<div>
16   - <%= link_to _('New category'), :action => 'new', :type => 'ProductCategory' %>
17   -</div>
18   -
19 10 <h1><%= _('Regions') %></h1>
20 11 <ul class='tree'>
21 12 <%= render :partial => 'category', :collection => @regions %>
... ...
app/views/manage_products/_add_input.html.erb
... ... @@ -1,25 +0,0 @@
1   -<div id='request_result_message' style='display: none'></div>
2   -
3   -<%= form_for(:input,
4   - :url => {:action => 'add_input', :id => @product},
5   - :html => {:method => 'post', :id => 'input-category-form'}
6   - ) do |f| %>
7   -
8   - <h3><%= _('Choose an input or raw material to this product:') %><span class='loading-area'></span></h3>
9   -
10   - <%= categories_container(select_for_new_category(@categories, @level)) %>
11   -
12   - <div id='categories_selection_actionbar'>
13   - <span id='save_and_continue_wrapper'>
14   - <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
15   - <span class='tooltip' id='save_and_continue_disabled_tooltip'>
16   - <%= ui_icon('ui-icon-alert') %>
17   - <%= _('This category does not allow registration of products, select a more specific category') %>
18   - </span>
19   - </span>
20   - <%= button :cancel, _('Cancel'), '#', :class => 'cancel-add-input' %>
21   - </div>
22   -
23   -<% end %>
24   -
25   -<%= javascript_tag "add_input_stuff()" %>
app/views/manage_products/_categories_autocomplete.html.erb
... ... @@ -1,8 +0,0 @@
1   -<%= text_field_tag 'product_category_id', '', :placeholder => _('type a category for the product') %>
2   -
3   -<%= javascript_include_tag '/javascripts/product_categories.js' %>
4   -<%= javascript_tag do %>
5   - product_categories.autocomplete.search_url = <%= url_for(:controller => :manage_products, :action => :search_categories).to_json %>
6   - product_categories.autocomplete.select_url = <%= url_for(:controller => :manage_products, :action => :show_category_tree).to_json %>
7   - product_categories.autocomplete.load('#product_category_id')
8   -<% end %>
app/views/manage_products/_categories_for_selection.html.erb
... ... @@ -1,10 +0,0 @@
1   -<%= select_for_categories(categories, level) %>
2   -
3   -<%= javascript_tag do %>
4   - jQuery(document).ready(function() {
5   - jQuery('#categories_container_wrapper').scrollTo('100%', 1000)
6   - jQuery('#selected_category_id').val(<%= @category.id rescue nil %>)
7   - jQuery('#hierarchy_navigation').html(<%= hierarchy_category_navigation(@category, :make_links => true).to_json %>)
8   - toggleDisabled(<%= (!!(@category && @category.accept_products?)).to_json %>, jQuery('#save_and_continue'))
9   - });
10   -<% end %>
app/views/manage_products/_certifiers_for_selection.html.erb
... ... @@ -1,4 +0,0 @@
1   -<%= select_certifiers(@qualifier) + remove_qualifier_button %>
2   -<%= javascript_tag do %>
3   - jQuery('#product-qualifiers-list *').removeClass('small-loading')
4   -<% end %>
app/views/manage_products/_display_category.html.erb
... ... @@ -1,4 +0,0 @@
1   -<div id='display-product-category'>
2   - <p class='hierarchy-category'></p>
3   - <%= edit_link( _('Change category'), { :action => 'edit_category', :id => @product.id}, :id => 'link-edit-product-category') %>
4   -</div>
app/views/manage_products/_display_description.html.erb
... ... @@ -1,15 +0,0 @@
1   -<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
2   -<% if !@product.description.blank? %>
3   - <%= @product.description %>
4   - <%= 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')) %>
5   -<% else %>
6   - <%= edit_product_ui_button_to_remote(
7   - @product,
8   - 'description',
9   - _('Add some description to your product'),
10   - 'data-primary-icon' => 'ui-icon-pencil',
11   - 'data-secondary-icon' => 'ui-icon-triangle-1-s',
12   - :title => _('Add a description to your product and give consumers more information about what you are advertising')
13   - ) %>
14   - <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-description')") %>
15   -<% end%>
app/views/manage_products/_display_image.html.erb
... ... @@ -1,11 +0,0 @@
1   -<div id='display-product-image'>
2   - <%= image_tag (@product.reload.default_image('big')), :class => 'product-pic' %>
3   -</div>
4   -
5   -<% if @product.image %>
6   - <%= link_to content_tag(:span, _('Zoom in')), @product.image.public_filename,
7   - :class => 'zoomify-image' %>
8   -<% end %>
9   -<%= add_zoom_to_images %>
10   -
11   -<%= edit_product_link_to_remote(@product, 'image', _('Change image')) %>
app/views/manage_products/_display_info.html.erb
... ... @@ -1,17 +0,0 @@
1   -<div id='display-product-info'>
2   - <%= display_value(@product) %>
3   - <%= display_availability(@product) %>
4   - <%= display_qualifiers(@product) %>
5   -
6   - <% if @product.has_basic_info? %>
7   - <%= 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')) %>
8   - <% else %>
9   - <%= edit_product_ui_button_to_remote(@product, 'info', _('Add price and other basic information'),
10   - :title => _('Click here to add price, discount and qualifiers/certifiers to make your product more attractive and detailed for the consumers'),
11   - 'data-primary-icon' => 'ui-icon-pencil',
12   - 'data-secondary-icon' => 'ui-icon-triangle-1-s')
13   - %>
14   - <%= javascript_tag("render_jquery_ui_buttons('edit-product-remote-button-ui-info')") %>
15   - <% end%>
16   -
17   -</div>
app/views/manage_products/_display_input.html.erb
... ... @@ -1,21 +0,0 @@
1   - <div class='input-informations input-form-closed'>
2   - <div class='input-name'> <%= input.name %> <%= input_icon(input) %> </div>
3   - <div class='input-details'>
4   - <% button_bar do %>
5   - <% if input.has_price_details? %>
6   - <%= edit_button(:edit, _('Edit'), {:action => 'edit_input', :id => input}, :class => 'edit-input', :id => "edit-input-#{input.id}") %>
7   - <% end %>
8   - <%= edit_button(:remove, _('Remove'), {action: 'remove_input', id: input}, data: {confirm: _('Are you sure that you want to remove this input or raw material?')}, class: 'remove-input', id: "remove-input-#{input.id}") %>
9   - <% end %>
10   - <% if input.has_price_details? %>
11   - <%= display_unit(input) %>
12   - <% else %>
13   - <%= edit_link(_('Click here to add price and the amount used'), {:action => 'edit_input', :id => input}, :class => 'add-input-details', :id => "add-input-#{input.id}-details") %>
14   - <% end %>
15   - </div>
16   - <div id='input-<%= input.id %>-form' class='input-details-form'> </div>
17   - </div>
18   -
19   - <% if user && user.has_permission?('manage_products', profile) %>
20   - <%= javascript_tag "input_javascript_stuff(#{input.id})" %>
21   - <% end %>
app/views/manage_products/_display_inputs.html.erb
... ... @@ -1,33 +0,0 @@
1   -<div id='new-product-input'></div>
2   -
3   -<div id='display-add-input-button'>
4   - <% if @product.inputs.empty? %>
5   - <%= edit_ui_button(
6   - _('Add the inputs or raw material used by this product'),
7   - {:action => 'add_input', :id => @product.id},
8   - :id => 'add-input-button',
9   - 'data-primary-icon' => 'ui-icon-pencil',
10   - 'data-secondary-icon' => 'ui-icon-triangle-1-s',
11   - :title => _('Add inputs or raw materials used by this product and give more transparency to consumers about your enterprise')
12   - ) %>
13   - <%= javascript_tag("render_jquery_ui_buttons('add-input-button')") %>
14   - <% else %>
15   - <%= 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')) %>
16   - <%= content_tag('span', _('Drag the input with the mouse to change the order'), :class => 'hint', :style => 'display: none') %>
17   - <% end %>
18   - <span class='loading-area'></span>
19   -</div>
20   -
21   -<div id='display-product-inputs'>
22   - <ul class='input-list'>
23   - <%= render :partial => 'manage_products/input', :collection => @inputs %>
24   - </ul>
25   - <%= edit_link(_('Order inputs'), {:action => 'order_inputs', :id => @product.id}, :class => "order-inputs", :style => 'display:none') %>
26   -</div>
27   -
28   -<% if user && user.has_permission?('manage_products', profile) %>
29   - <% if @product.inputs.size > 1 %>
30   - <%= javascript_tag "input_javascript_ordering_stuff()" %>
31   - <% end %>
32   - <%= javascript_tag "display_input_stuff()" %>
33   -<% end %>
app/views/manage_products/_display_name.html.erb
... ... @@ -1,13 +0,0 @@
1   -<div id='display-product-name'>
2   - <h2><%= @product.name_with_unit %></h2>
3   - <%= edit_product_link_to_remote(@product, 'name', _('Edit name and unit'), :title => _('Click here to edit the name of your product and the unit')) %>
4   -</div>
5   -<%= javascript_tag do %>
6   - jQuery('#display-product-category .hierarchy-category').first().html('<%=
7   - escape_javascript(hierarchy_category_navigation(
8   - @product.product_category,
9   - :make_links => false,
10   - :hide_current_category => @product.name_is_blank?)
11   - )
12   - %>')
13   -<% end %>
app/views/manage_products/_display_price_details.html.erb
... ... @@ -1,18 +0,0 @@
1   -<div id='display-manage-price-details'></div>
2   -
3   -<div id='display-price-details'>
4   - <ul class='price-details-list'>
5   - <li>
6   - <div class='price-detail-name'><%= _('Inputs:') %></div>
7   - <div class='price-detail-price inputs-cost'>
8   - <span><%= float_to_currency(@product.inputs_cost) %></span>
9   - </div>
10   - </li>
11   - <% @product.price_details.each do |price_detail| %>
12   - <li>
13   - <div class='price-detail-name'><%= "%s:" % price_detail.name %></div>
14   - <div class='price-detail-price'><%= float_to_currency(price_detail.price) %></div>
15   - </li>
16   - <% end %>
17   - </ul>
18   -</div>
app/views/manage_products/_edit_description.html.erb
... ... @@ -1,14 +0,0 @@
1   -<%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
2   -<%= remote_form_for(@product,
3   - :loading => "small_loading('product-description-form')",
4   - :update => 'product-description',
5   - :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'},
6   - :html => {:id => 'product-description-form', :method => 'post'}) do |f| %>
7   -
8   - <%= labelled_form_field(_('Description:'), f.text_area(:description, :rows => 15, :style => 'width: 90%;', :class => 'mceEditor')) %>
9   - <% button_bar do %>
10   - <%= submit_button :save, _('Save') %>
11   - <%= cancel_edit_product_link(@product, 'description') %>
12   - <% end %>
13   -
14   -<% end %>
app/views/manage_products/_edit_image.html.erb
... ... @@ -1,26 +0,0 @@
1   -<div id='display-product-image'>
2   - <%= image_tag (@product.reload.default_image('thumb')), :class => 'product-pic' %>
3   -</div>
4   -
5   -<%= form_for(:product, :url => { :controller => 'manage_products', :action => 'edit', :id => @product, :field => 'image' }, :html => { :method => 'post', :id => 'uploadForm', :multipart => true}) do |f| %>
6   - <%= f.fields_for :image_builder, @product.image do |i| %>
7   - <%= i.file_field( :uploaded_data, { :size => 10 } ) %>
8   - <p><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %></p>
9   - <% end %>
10   -
11   - <%= submit_button 'save', _('Save') %>
12   - <%= cancel_edit_product_link(@product, 'image') %>
13   -<% end %>
14   -
15   -<script type="text/javascript">
16   - jQuery("#uploadForm").ajaxForm({
17   - beforeSubmit: function(a,f,o) {
18   - o.loading = small_loading("uploadForm");
19   - },
20   - target: '#product-image'
21   - });
22   -</script>
23   -
24   -<% if errors %>
25   - <%= render_dialog_error_messages 'product' %>
26   -<% end %>
app/views/manage_products/_edit_info.html.erb
... ... @@ -1,63 +0,0 @@
1   -<% if errors %>
2   - <%= render_dialog_error_messages 'product' %>
3   -<% end %>
4   -
5   -<%= remote_form_for(@product,
6   - :loading => "small_loading('product-info-form')",
7   - :update => 'product-info',
8   - :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'info'},
9   - :html => {:id => 'product-info-form', :method => 'post'}) do |f| %>
10   -
11   - <table>
12   - <tr>
13   - <td><%= f.label :price, _('Price (%s)') % environment.currency_unit, :class => 'formlabel' %></td>
14   - <td class='formfield'><%= f.text_field(:price, :value => @product.formatted_value(:price), :class => 'numbers-only') %></td>
15   - </tr>
16   - <tr>
17   - <td><%= f.label :discount, _('Discount (%s)') % environment.currency_unit, :class => 'formlabel' %></td>
18   - <td class='formfield'><%= 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')) %></td>
19   - </tr>
20   - <tr>
21   - <td class='formlabel'><%= _('Available') %></td>
22   - <td class='formfield'><%= labelled_radio_button( _('Yes'), 'product[available]', true, @product.available, :id => 'product_available') + labelled_radio_button( _('No'), 'product[available]', false, !@product.available) %></td>
23   - </tr>
24   - <tr>
25   - <td><%= f.label :highlighted, _('Highlight this product?'), :class => 'formlabel' %></td>
26   - <td class='formfield'><%= f.check_box(:highlighted) %></td>
27   - </tr>
28   - </table>
29   -
30   - <% if !environment.qualifiers.empty? %>
31   - <table id='product-qualifiers-list'>
32   - <tr>
33   - <th><%= _('Qualifier') %></th>
34   - <th><%= _('Certifier') %></th>
35   - </tr>
36   - <% @product.qualifiers.each_with_index do |qualifier, index| %>
37   - <tr>
38   - <td>
39   - <%= select_qualifiers(@product, qualifier.id) %>
40   - </td>
41   - <td id='certifier-area-<%= index %>'>
42   - <%= select_certifiers(qualifier, @product) + remove_qualifier_button %>
43   - </td>
44   - </tr>
45   - <% end %>
46   - </table>
47   - <%= button_to_function(
48   - :add,
49   - _('Add new qualifier'),
50   - "new_qualifier_row('#product-qualifiers-list', '#{escape_javascript(CGI::escape_html(select_qualifiers(@product)))}', '#{escape_javascript(CGI::escape_html(remove_qualifier_button))}')"
51   - ) %>
52   - <%= hidden_field_tag "product[qualifiers_list][nil]" %>
53   - <% end %>
54   -
55   - <%= hidden_field_tag 'info-bar-update-url', @product.price_composition_bar_display_url, :class => 'bar-update-url' %>
56   -
57   - <% button_bar do %>
58   - <%= submit_button :save, _('Save') %>
59   - <%= cancel_edit_product_link(@product, 'info') %>
60   - <% end %>
61   -<% end %>
62   -
63   -<%= render :partial => 'shared/numbers_only_javascript' %>
app/views/manage_products/_edit_input.html.erb
... ... @@ -1,43 +0,0 @@
1   -<%= form_for(:input, :url => {:controller => 'manage_products', :action => 'edit_input', :id => @input},
2   - :html => {:method => 'post', :id => "edit-input-#{ @input.id }-form"}) do |f| %>
3   -
4   - <%= hidden_field_tag 'input-bar-update-url', @input.product.price_composition_bar_display_url, :class => 'bar-update-url' %>
5   - <%= hidden_field_tag 'inputs-cost-update-url', @input.product.inputs_cost_update_url %>
6   -
7   - <table>
8   - <tr>
9   - <td><%= f.label :amount_used, label_amount_used(@input), :class => 'formlabel' %></td>
10   - <td class='formfield'><%= f.text_field(:amount_used, :value => @input.formatted_amount, :class => 'numbers-only amount-used') + select_unit(@input) %></td>
11   - </tr>
12   - <tr>
13   - <td><%= f.label :price_per_unit, _('Price %s (%s)') % [display_price_by(@input.unit), environment.currency_unit], :class => 'formlabel' %></td>
14   - <td class='formfield'><%= f.text_field(:price_per_unit, :value => @input.formatted_value(:price_per_unit), :class => 'numbers-only price-per-unit') %></td>
15   - </tr>
16   - <tr>
17   - <td class='formlabel'><%= _("This input or raw material inpact on the final price of the product?") %></td>
18   - <td>
19   - <%= radio_button :input, 'relevant_to_price', true %>
20   - <label for="input_relevant_to_price"><%= _('Yes') %></label>
21   - <%= radio_button :input, 'relevant_to_price', false %>
22   - <label for="input_relevant_to_price"><%= _('No') %></label>
23   - </td>
24   - </tr>
25   - <tr>
26   - <td class='formlabel'><%= _('Is it from solidarity economy?') %></td>
27   - <td>
28   - <%= radio_button :input, 'is_from_solidarity_economy', true %>
29   - <label for="input_is_from_solidarity_economy"><%= _('Yes') %></label>
30   - <%= radio_button :input, 'is_from_solidarity_economy', false %>
31   - <label for="input_is_from_solidarity_economy"><%= _('No') %></label>
32   - </td>
33   - </tr>
34   - <tr>
35   - <td colspan='2'>
36   - <%= submit_button :save, _('Save'), :title => _('Save changes of this input or raw material') %>
37   - <%= button :cancel, _('Cancel'), '#', :class => 'cancel-edit-input', :id => "cancel-edit-input-#{@input.id}", :title => _('Cancel changes of this input or raw material') %>
38   - <td>
39   - <tr>
40   - </table>
41   -<% end %>
42   -
43   -<%= javascript_tag "edit_input_stuff(#{@input.id}, '#{environment.currency_separator}')" %>
app/views/manage_products/_edit_name.html.erb
... ... @@ -1,21 +0,0 @@
1   -<%= remote_form_for(@product,
2   - :loading => "small_loading('product-name-form')",
3   - :update => 'product-name',
4   - :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'name'},
5   - :html => {:method => 'post', :id => 'product-name-form'}) do |f| %>
6   - <%= f.text_field(:name, :value => @product.name, :class => 'name_edition') %>
7   - <%= select_unit(@product) %>
8   -
9   - <% button_bar do %>
10   - <%= submit_button :save, _('Save') %>
11   - <%= cancel_edit_product_link(@product, 'name') %>
12   - <% end %>
13   -<% end %>
14   -
15   -<script type="text/javascript">
16   - jQuery('#product_name').focus().select();
17   -</script>
18   -
19   -<% if errors %>
20   - <%= render_dialog_error_messages 'product' %>
21   -<% end %>
app/views/manage_products/_edit_price_details.html.erb
... ... @@ -1,14 +0,0 @@
1   -<% price_details.each do |price_detail| %>
2   - <tr id='<%= "price-detail-#{price_detail.id}" %>'>
3   - <td><%= select_production_cost(@product, price_detail.production_cost_id) %></td>
4   - <td><%= 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)) %></td>
5   - <td>
6   - <%= link_to_remote(_('Remove'),
7   - :update => "price-detail-#{price_detail.id}",
8   - :complete => "calculateValuesForBar();",
9   - data: {confirm: _('Are you sure that you want to remove this cost?')},
10   - :url => { :action => 'remove_price_detail', :id => price_detail, :product => @product }) %>
11   - </tr>
12   -<% end %>
13   -
14   -<%= render :partial => 'shared/numbers_only_javascript' %>
app/views/manage_products/_form.html.erb
... ... @@ -1,17 +0,0 @@
1   -<%= error_messages_for :product %> <br/>
2   -
3   -<%= form_for :product, :html => {:multipart => true }, :url => {:action => mode} do |f| %>
4   - <%= required_fields_message %>
5   -
6   - <%= display_form_field( _('Name:'), f.text_field(:name) ) %>
7   - <%= display_form_field( _('Price:'), f.text_field(:price) ) %>
8   - <%= display_form_field( _('Description:'), f.text_area(:description, :rows => 10, :class => 'mceEditor') ) %>
9   - <%= labelled_form_field(f.check_box(:highlighted) + _('Highlight this product'),'') %>
10   - <%= f.fields_for :image_builder, @product.image do |i| %>
11   - <%= file_field_or_thumbnail(_('Image:'), @product.image, i) %>
12   - <% end %>
13   -
14   - <% button_bar do %>
15   - <%= submit_button('save', (mode == 'new' ? _('Create product') : _('Save changes')), :cancel => {:action => 'index'} ) %>
16   - <% end %>
17   -<% end %>
app/views/manage_products/_input.html.erb
... ... @@ -1,3 +0,0 @@
1   -<li class='input-item' id="input-<%= input.id %>">
2   -<%= render :partial => 'manage_products/display_input', :locals =>{:input => input} %>
3   -</li>
app/views/manage_products/_manage_product_details.html.erb
... ... @@ -1,43 +0,0 @@
1   -<div id='price-composition-bar'>
2   - <%= render :partial => 'manage_products/price_composition_bar' %>
3   -</div>
4   -
5   -<%= form_tag({:action => 'manage_product_details'}, :method => 'post', :id => 'manage-product-details-form') do %>
6   - <div>
7   - <table id='display-product-price-details'>
8   - <tr>
9   - <td><%= _('Inputs') %></td>
10   - <td class='inputs-cost'>
11   - <span><%= float_to_currency(@product.inputs_cost) %></span>
12   - </td>
13   - <td>
14   - <small><%= _('This value is composed by the total value of registered inputs') %></small>
15   - </td>
16   - </tr>
17   - <%= render :partial => 'manage_products/edit_price_details', :locals => {:price_details => @product.price_details} %>
18   - </table>
19   - </div>
20   -
21   - <%= hidden_field(:product, :inputs_cost) %>
22   - <%= hidden_field(:product, :price) %>
23   -
24   - <% button_bar do %>
25   - <%= submit_button :save, _('Save'), :disabled => '', :class => 'disabled' %>
26   - <%= 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?')} %>
27   - <%= button(:add, _('New cost'), '#', :id => 'add-new-cost') %>
28   - <span class='loading-area'></span>
29   - <% end %>
30   -
31   -<% end %>
32   -
33   -<div style='display:none'>
34   - <table id='new-cost-fields'>
35   - <tr>
36   - <td><%= select_production_cost(@product) %></td>
37   - <td><%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', nil, :class => 'numbers-only price-details-price', :size => 6)) %></td>
38   - <td><%= link_to(_('Cancel'), '#', {:class => 'cancel-new-cost'}) %></td>
39   - </tr>
40   - </table>
41   -</div>
42   -
43   -<%= render :partial => 'shared/numbers_only_javascript' %>
app/views/manage_products/_price_composition_bar.html.erb
... ... @@ -1,22 +0,0 @@
1   -<%= javascript_tag do %>
2   - var value = <%= @product.price_description_percentage %>;
3   - var total_cost = <%= @product.total_production_cost %>;
4   - var price = '<%= @product.formatted_value(:price) %>';
5   - var described = false;
6   - var currency_format = { separator : '<%= environment.currency_separator %>', delimiter : '<%= environment.currency_delimiter %>', unit : '<%= environment.currency_unit %>' };
7   - if (<%= @product.price_described? %>) {
8   - var described = true;
9   - }
10   - priceCompositionBar(value,described,total_cost,price);
11   -<% end %>
12   -
13   -<div id="price-details-info">
14   - <div id="details-progressbar">
15   - <div id='progressbar'></div>
16   - <div id='progressbar-text'>
17   - <%= price_composition_progressbar_text(@product) %>
18   - </div>
19   - </div>
20   - <div id='progressbar-icon' class='ui-icon ui-icon-info' data-price-not-described-message='<%= _("The production cost of your product is not described yet. If you want to display the price composition, please add all the costs") %>' data-price-described-message='<%= _("The production cost of your product is fully described and will be displayed on your product's page") %>' data-price-described-notice='<%= _("Congratulations! Now the price is open to the public") %>'>
21   -</div>
22   -</div>
app/views/manage_products/_price_details_button.html.erb
... ... @@ -1,10 +0,0 @@
1   -<%= edit_ui_button(
2   - _('Describe here the cost of production'),
3   - {:action => 'manage_product_details', :id => @product.id},
4   - :id => 'manage-product-details-button',
5   - 'data-primary-icon' => 'ui-icon-pencil',
6   - 'data-secondary-icon' => 'ui-icon-triangle-1-s',
7   - :title => _('Describe details about how the price was defined')
8   -) %>
9   -<%= javascript_tag("render_jquery_ui_buttons('manage-product-details-button')") %>
10   -<span class='loading-area'></span>
app/views/manage_products/_selected_category_tree.html.erb
... ... @@ -1,2 +0,0 @@
1   -<%= categories_container selects_for_all_ancestors(@category), hierarchy_category_navigation(@category, :make_links => true) %>
2   -
app/views/manage_products/edit.html.erb
... ... @@ -1,3 +0,0 @@
1   -<h2> <%= _('Editing') %> <%= @product.name %> </h2>
2   -
3   -<%= render :partial => 'manage_products/form', :locals => {:mode => 'edit'} %>
app/views/manage_products/edit_category.html.erb
... ... @@ -1,33 +0,0 @@
1   -<div class=product-category-hierarchy>
2   - <%= hierarchy_category_navigation(@category, :make_links => false)%>
3   -</div>
4   -
5   -<div id="category-product-edition">
6   -
7   - <h2><%= @product.name %></h2>
8   -
9   - <div id='request_result_message' style='display: none'></div>
10   -
11   - <%= remote_form_for(@product,
12   - :loading => "open_loading('#{ _('loading...') }')",
13   - :update => "request_result_message",
14   - :url => {:action => 'edit_category', :id => @product},
15   - :html => {:method => 'post', :id => 'category_form'}) do |f| %>
16   -
17   - <h3><%= _('Edit category of this product:') %></h3>
18   -
19   - <%= render 'manage_products/selected_category_tree' %>
20   -
21   - <div id='categories_selection_actionbar'>
22   - <%= button(:back, _('Back to product'), :action => 'show', :id => @product) %>
23   - <span id='save_and_continue_wrapper'>
24   - <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
25   - <span class='tooltip' id='save_and_continue_disabled_tooltip'>
26   - <%= ui_icon('ui-icon-alert') %>
27   - <%= _('This category does not allow registration of products, select a more specific category') %>
28   - </span>
29   - </span>
30   - </div>
31   -
32   - <% end %>
33   -</div>
app/views/manage_products/index.html.erb
... ... @@ -1,30 +0,0 @@
1   -<h2> <%=_('Listing products and services') %> </h2>
2   -
3   -<table>
4   - <tr>
5   - <th><%= _('Product') %></th>
6   - <th><%= _('Price') %></th>
7   - <th><%= _('Actions') %></th>
8   - </tr>
9   - <% if @products.empty? %>
10   - <tr>
11   - <td colspan='3' style='text-align: center; padding: 10px'><em><%= _('(no product registered yet)') %></em></td>
12   - </tr>
13   - <% end %>
14   - <% @products.each do |product| %>
15   - <tr>
16   - <td><strong><%= link_to product.name, :action => 'show', :id => product %></strong></td>
17   - <td><%= product.price %></td>
18   - <td>
19   - <%= button :delete, _('Remove'), {action: 'destroy', id: product}, data: {confirm: _('Are you sure you want to remove this product?')} %>
20   - </td>
21   - </tr>
22   - <% end %>
23   -</table>
24   -
25   -<%= pagination_links @products %>
26   -
27   -<% button_bar do %>
28   - <%= button :add, _('New product or service'), :action => 'new' if @profile.create_product? %>
29   - <%= button :back, _('Back'), { :controller => 'profile_editor', :profile => @profile.identifier, :action => 'index' } %>
30   -<% end %>
app/views/manage_products/new.html.erb
... ... @@ -1,30 +0,0 @@
1   -<h2 id='new_product_title'><%= _('New product or service') %></h2>
2   -
3   -<div id='request_result_message' style='display: none'></div>
4   -
5   -<%= remote_form_for @product,
6   - :loading => "open_loading('#{ _('loading...') }')",
7   - :update => "request_result_message",
8   - :url => {:action => 'new'},
9   - :html => {:method => 'post', :id => 'category_form'} do |f| %>
10   -
11   - <h3><%= _('Select the category of the new product or service') %></h3>
12   -
13   - <%= categories_container(select_for_new_category(@categories, @level)) %>
14   -
15   - <div id='categories_selection_actionbar'>
16   - <%= button :back, _('Back to the product listing'), :action => 'index' %>
17   - <span id='save_and_continue_wrapper'>
18   - <%= submit_button(:save, _('Save and continue'), :id => 'save_and_continue') %>
19   - <span class='tooltip' id='save_and_continue_disabled_tooltip'>
20   - <%= ui_icon('ui-icon-alert') %>
21   - <%= _('This category does not allow registration of products, select a more specific category') %>
22   - </span>
23   - </span>
24   - </div>
25   -
26   -<% end %>
27   -
28   -<%= javascript_tag do %>
29   - toggleDisabled(<%= @category && @category.accept_products? ? 'true' : 'false' %>, jQuery('#save_and_continue')[0])
30   -<% end %>
app/views/manage_products/show.html.erb
... ... @@ -1,74 +0,0 @@
1   -<div id="product-category">
2   - <%= render :partial => 'manage_products/display_category' %>
3   -</div>
4   -
5   -<div id="show_product">
6   -
7   - <div id='product-name'>
8   - <%= render :partial => 'manage_products/display_name' %>
9   - </div>
10   -
11   - <div id='product-details'>
12   - <div id='product-image' class="zoomable-image">
13   - <%= render :partial => 'manage_products/display_image' %>
14   - </div>
15   - <div id='product-extra-content'>
16   - <% extra_content = @plugins.dispatch(:product_info_extras, @product).collect { |content| instance_exec(&content) } %>
17   - <%= safe_join(extra_content, "\n") %>
18   - </div>
19   - <div id='product-info'>
20   - <%= render :partial => 'manage_products/display_info' %>
21   - </div>
22   - </div>
23   -
24   - <br style='clear: both'/>
25   -
26   - <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty? && !@product.price_described? ) %>
27   - <% plugins_tabs = plugins_product_tabs %>
28   -
29   - <div class='ui-tabs' id='product-<%= @product.id %>-tabs'>
30   - <ul>
31   - <% if !@product.description.blank? || @allowed_user %>
32   - <li class='tab'><a href='#product-description'><%= _('Description') %></a></li>
33   - <% end %>
34   - <% if !@product.inputs.empty? || @allowed_user %>
35   - <li class='tab'><a href='#product-inputs'><%= _('Inputs and raw material') %></a></li>
36   - <% end %>
37   - <% if @product.price_described? || @allowed_user %>
38   - <li class='tab'><a href='#product-price-details'><%= _('Price composition') %></a></li>
39   - <% end %>
40   -
41   - <% plugins_tabs.each do |tab| %>
42   - <li class='tab'><a href='#<%=tab[:id]%>'><%= tab[:title] %></a></li>
43   - <% end %>
44   -
45   - </ul>
46   -
47   - <div id='product-description'>
48   - <%= render :partial => 'manage_products/display_description' %>
49   - </div>
50   -
51   - <div id='product-inputs'>
52   - <%= render :partial => 'manage_products/display_inputs' %>
53   - </div>
54   -
55   - <% if @product.price_described? || @allowed_user %>
56   - <div id='product-price-details'>
57   - <%= render :partial => 'manage_products/display_price_details' %>
58   - <%= render :partial => 'manage_products/price_details_button' %>
59   - </div>
60   - <% end %>
61   -
62   - <% plugins_tabs.each do |tab| %>
63   - <div id='<%=tab[:id]%>'><%= raw tab[:content] %></div>
64   - <% end %>
65   -
66   - </div>
67   - <% end %>
68   -
69   -</div>
70   -
71   -<% button_bar do %>
72   - <%= button :back, _('Back to the product listing'), :controller => 'catalog', :action => 'index' %>
73   - <%= button :delete, _('Remove product or service'), {:action => 'destroy', :id => @product}, :class => 'requires-permission-manage_products', :style => 'display:none;' %>
74   -<% end %>
app/views/map_balloon/profile.html.erb
... ... @@ -17,7 +17,7 @@
17 17 <strong><%= _('Address: ') + @profile.address %></strong><br/>
18 18 <% end %>
19 19 <% if @profile.respond_to?(:products) and !@profile.products.blank? %>
20   - <strong><%= _('Products/Services: ') + @profile.products.map{|i| link_to(i.name, :controller => 'manage_products', :profile => @profile.identifier, :action => 'show', :id => i.id)}.join(', ') %></strong><br/>
  20 + <strong><%= _('Products/Services: ') + @profile.products.map{|i| link_to(i.name, controller: 'products_plugin/page', profile: @profile.identifier, action: 'show', id: i.id)}.join(', ') %></strong><br/>
21 21 <% end %>
22 22 <% if @profile.respond_to?(:distance) and !@profile.distance.nil? %>
23 23 <strong><%= _('Distance: ') + "%.2f%" % @profile.distance %></strong><br/>
... ...
app/views/person_notifier/mailer/_create_product.html.erb
... ... @@ -1 +0,0 @@
1   -../../profile/_create_product.html.erb
2 0 \ No newline at end of file
app/views/person_notifier/mailer/_remove_product.html.erb
... ... @@ -1 +0,0 @@
1   -../../profile/_remove_product.html.erb
2 0 \ No newline at end of file
app/views/person_notifier/mailer/_update_product.html.erb
... ... @@ -1 +0,0 @@
1   -../../profile/_update_product.html.erb
2 0 \ No newline at end of file
app/views/profile/_create_product.html.erb
... ... @@ -1,13 +0,0 @@
1   -<div class='profile-activity-image'>
2   - <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
3   -</div>
4   -<div class='profile-activity-description'>
5   - <p class='profile-activity-text'><%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_in_words activity.created_at %></p>
7   -
8   - <div class='profile-wall-actions'>
9   - <%= 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 %>
10   - </div>
11   -</div>
12   -
13   -<div style="clear: both"></div>
app/views/profile/_remove_product.html.erb
... ... @@ -1,12 +0,0 @@
1   -<div class='profile-activity-image'>
2   -</div>
3   -<div class='profile-activity-description'>
4   - <p class='profile-activity-text'><%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %></p>
5   - <p class='profile-activity-time'><%= time_ago_in_words activity.created_at %></p>
6   -
7   - <div class='profile-wall-actions'>
8   - <%= 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 %>
9   - </div>
10   -</div>
11   -
12   -<div style="clear: both"></div>
app/views/profile/_update_product.html.erb
... ... @@ -1,13 +0,0 @@
1   -<div class='profile-activity-image'>
2   - <%= link_to image_tag(activity.target.default_image :minor), activity.target.url, class: 'product-pic' if activity.target.present? %>
3   -</div>
4   -<div class='profile-activity-description'>
5   - <p class='profile-activity-text'><%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_in_words activity.created_at %></p>
7   -
8   - <div class='profile-wall-actions'>
9   - <%= 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 %>
10   - </div>
11   -</div>
12   -
13   -<div style="clear: both"></div>
app/views/profile_editor/_organization.html.erb
... ... @@ -66,8 +66,3 @@
66 66 <%= labelled_check_box(_('Enable "contact us"'), 'profile_data[enable_contact_us]', "1", @profile.enable_contact_us) if @profile.enterprise? %>
67 67  
68 68 <%= render :partial => 'moderation', :locals => { :profile => @profile } %>
69   -
70   -<% if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') %>
71   - <h2><%=_('Products/Services catalog')%></h2>
72   - <%= labelled_form_field(_('Number of products/services displayed per page on catalog'), text_field(:profile_data, :products_per_catalog_page, :size => 3)) %>
73   -<% end %>
... ...
app/views/profile_editor/index.html.erb
... ... @@ -47,8 +47,6 @@
47 47  
48 48 <%= control_panel_button(_('Manage Members'), 'members', :controller => 'profile_members') if profile.organization? && user.has_permission?(:manage_memberships, profile) %>
49 49  
50   - <%= control_panel_button(_('Manage Products/Services'), 'products', :controller => 'manage_products') if profile.enterprise? && environment.enabled?('products_for_enterprises') %>
51   -
52 50 <% if !environment.enabled?('disable_asset_enterprises') %>
53 51 <% if profile.is_validation_entity? %>
54 52 <%= control_panel_button(_('Enterprise Validation'), 'validation', :controller => 'enterprise_validation') %>
... ...
app/views/search/_display_results.html.erb
... ... @@ -17,9 +17,10 @@
17 17 <div class="search-results-innerbox search-results-type-<%= name.to_s.singularize %> <%= 'common-profile-list-block' if SearchHelper::COMMON_PROFILE_LIST_BLOCK.include?(name) %>">
18 18 <ul>
19 19 <% search[:results].each do |hit| %>
20   - <% partial = partial_for_class(hit.class, display) %>
21   - <% variable_name = partial.gsub("#{display}_", '').to_sym %>
22   - <%= render :partial => partial, :locals => {variable_name => hit} %>
  20 + <%= render_for_class hit.class do |klass| %>
  21 + <% name = klass.name.underscore %>
  22 + <%= render partial_name_for(name, display), name.split('/').last.to_sym => hit %>
  23 + <% end %>
23 24 <% end %>
24 25 </ul>
25 26 </div>
... ...
app/views/search/_full_product.html.erb
... ... @@ -1,85 +0,0 @@
1   -<% extra_content = @plugins.dispatch(:asset_product_extras, product).collect { |content| instance_exec(&content) } %>
2   -<% extra_properties = @plugins.dispatch(:asset_product_properties, product) %>
3   -
4   -<li class="search-product-item <%= 'highlighted' if product.highlighted? %>">
5   -
6   - <div class="search-product-item-first-column">
7   - <%= render :partial => 'search/image', :object => product %>
8   -
9   - <% if product.available %>
10   - <% if product.price && product.price > 0 %>
11   - <% has_discount = product.discount && product.discount > 0 %>
12   - <% if product.price %>
13   - <span class="search-product-price-textid"><%=_("from") if has_discount %></span><%= price_span(product.price, :class => "search-product-price " + (has_discount ? 'with-discount' : '')) %>
14   - <% if has_discount %>
15   - <span class="search-product-price-textid"><%=_("by")%></span><%= price_span(product.price_with_discount, :class => "search-product-price") %>
16   - <% end %>
17   - <% if product.unit %>
18   - <span class="search-product-unit">&nbsp;<%= _('/') %>&nbsp;<%= product.unit.name %></span>
19   - <% end %>
20   - <% end %>
21   - <div class="search-product-inputs-info">
22   - <% if p = product.percentage_from_solidarity_economy %>
23   - <div class="search-product-percentage-from-solidarity-economy search-product-ecosol-percentage-icon-<%= p[0].to_s %>"
24   - title="<%=_('Percentage of inputs from solidarity economy')%>">
25   - <%= p[1] %>
26   - </div>
27   - <% end %>
28   -
29   - <% if product.price_described? %>
30   - <% title = (product.inputs.relevant_to_price + product.price_details).map{ |i|
31   - '<div class="search-product-input-dots-to-price">' +
32   - '<div class="search-product-input-name">' + i.name + '</div>' +
33   - price_span(i.price, :class => 'search-product-input-price') +
34   - '</div>' }.join('') %>
35   - <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %>
36   - <% end %>
37   - </div>
38   - <% end %>
39   - <% else %>
40   - <span class="product-not-available"><%= _('Not available') %></div>
41   - <% end %>
42   -
43   - </div>
44   - <div class="search-product-item-second-column">
45   - <%= link_to_product product, :class => 'search-result-title' %>
46   - <div class="search-product-supplier">
47   - <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage product.enterprise.name, product.enterprise %>
48   - </div>
49   - <div class="search-product-description">
50   - <% if product.description %>
51   - <% desc_stripped = strip_tags(product.description) %>
52   - <span class="search-field-label"><%= _('Description') %> </span><%= excerpt desc_stripped, desc_stripped.first(3), radius: 300 %>
53   - <% end %>
54   - </div>
55   - </div>
56   - <div class="search-product-item-third-column">
57   - <div class="search-product-region">
58   - <% if product.enterprise.region %>
59   - <span class="search-field-label"><%= _('City') %></span>
60   - <br /><%= city_with_state(product.enterprise.region) %>
61   - <% end %>
62   - </div>
63   - <div class="search-product-qualifiers">
64   - <% if product.product_qualifiers.count > 0 %>
65   - <span class="search-field-label"><%= _('Qualifiers') %></span>
66   - <% product.product_qualifiers.each do |pq| %>
67   - <% if pq.qualifier %>
68   - <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span>
69   - <% end %>
70   - <% if pq.certifier %>
71   - <span class="search-product-certifier">&nbsp;<%= _('cert. ') + pq.certifier.name + _(";") %></span>
72   - <% end %>
73   - <% end %>
74   - <% end %>
75   - </div>
76   - </div>
77   -
78   - <div style="clear: both"></div>
79   -
80   - <%= safe_join(extra_content, '\n') %>
81   - <% extra_properties.each do |property| %>
82   - <div><%= ''.html_safe + property[:name] + ': ' + instance_exec(&property[:content]) %></div>
83   - <% end %>
84   -
85   -</li>
app/views/search/_image.html.erb
... ... @@ -36,17 +36,6 @@
36 36 <div class="search-no-image"><span><%= _('No image') %></span></div>
37 37 <% end %>
38 38 </div>
39   - <% elsif image.is_a? Product %>
40   - <% if image.image %>
41   - <div class="zoomable-image">
42   - <%= link_to '', product_path(image), :class => "search-image-pic",
43   - :style => 'background-image: url(%s)'% image.default_image(:thumb) %>
44   - <%= link_to content_tag(:span, _('Zoom in')), image.image.public_filename,
45   - :class => 'zoomify-image' %>
46   - </div>
47   - <% else %>
48   - <div class="search-no-image"><span><%= _('No image') %></span></div>
49   - <% end %>
50 39 <% else %>
51 40 <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div>
52 41 <% end %>
... ...
app/views/search/products.html.erb
... ... @@ -1 +0,0 @@
1   -search_page.html.erb
2 0 \ No newline at end of file
app/views/search/products.js.erb
... ... @@ -1 +0,0 @@
1   -search.js.erb
2 0 \ No newline at end of file
config/initializers/action_tracker.rb
... ... @@ -32,15 +32,6 @@ ActionTrackerConfig.verbs = {
32 32 reply_scrap_on_self: {
33 33 },
34 34  
35   - create_product: {
36   - },
37   -
38   - update_product: {
39   - },
40   -
41   - remove_product: {
42   - },
43   -
44 35 favorite_enterprise: {
45 36 },
46 37  
... ...
config/routes.rb
... ... @@ -56,6 +56,13 @@ Noosfero::Application.routes.draw do
56 56 # search
57 57 match 'search(/:action(/*category_path))', controller: 'search', via: :all
58 58  
  59 + ##
  60 + # Keep products URL compatibility
  61 + get 'catalog/:profile', to: redirect{ |params, request| "/profile/#{request.params[:profile]}/plugin/products/catalog" }
  62 + get 'myprofile/:profile/manage_products(/:action(/:id))', to: (redirect do |params, request|
  63 + "/profile/#{request.params[:profile]}/plugin/products/page/#{request.params[:action]}/#{request.params[:id]}"
  64 + end)
  65 +
59 66 # events
60 67 match 'profile/:profile/events_by_day', controller: 'events', action: 'events_by_day', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
61 68 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
63 70 match 'profile/:profile/events/:year/:month', controller: 'events', action: 'events', year: /\d*/, month: /\d*/, profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
64 71 match 'profile/:profile/events', controller: 'events', action: 'events', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
65 72  
66   - # catalog
67   - match 'catalog/:profile', controller: 'catalog', action: 'index', profile: /#{Noosfero.identifier_format_in_url}/i, as: :catalog, via: :all
68   -
69 73 # invite
70 74 match 'profile/:profile/invite/friends', controller: 'invite', action: 'invite_friends', profile: /#{Noosfero.identifier_format_in_url}/i, via: :all
71 75 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
95 99 # chat
96 100 match 'chat(/:action(/:id))', controller: 'chat', via: :all
97 101  
  102 +
98 103 ######################################################
99 104 ## Controllers that are profile-specific (for profile admins )
100 105 ######################################################
... ...
db/migrate/20160422163123_enable_products_plugin_on_environments.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +class Product < ApplicationRecord
  2 +end
  3 +class Profile < ApplicationRecord
  4 + has_many :products
  5 +end
  6 +class Environment < ApplicationRecord
  7 + has_many :profiles
  8 + has_many :products, through: :profiles
  9 +
  10 + acts_as_having_settings field: :settings
  11 + settings_items :enabled_plugins, type: Array
  12 +end
  13 +
  14 +class EnableProductsPluginOnEnvironments < ActiveRecord::Migration
  15 +
  16 + def up
  17 + environments = Environment.all
  18 + products_used = environments.any?{ |e| e.products.count > 0 }
  19 + return unless products_used
  20 +
  21 + Bundler.clean_system 'script/noosfero-plugins enable products'
  22 + environments.each do |e|
  23 + next unless e.products.count > 0
  24 + e.enabled_plugins << 'ProductsPlugin'
  25 + e.save!
  26 + end
  27 + end
  28 +
  29 + def down
  30 + say "this migration can't be reverted"
  31 + end
  32 +
  33 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended that you check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(version: 20160408011720) do
  14 +ActiveRecord::Schema.define(version: 20160422163123) do
15 15  
16 16 # These are extensions that must be enabled in order to support this database
17 17 enable_extension "plpgsql"
... ...
features/browse_catalogs.feature
... ... @@ -1,317 +0,0 @@
1   -Feature: browse catalogs
2   - As a noosfero visitor
3   - I want to browse catalogs of products
4   -
5   - Background:
6   - Given the following users
7   - | login | name |
8   - | joaosilva | Joao Silva |
9   - And the following enterprises
10   - | identifier | owner | name | enabled |
11   - | artebonito | joaosilva | Associação de Artesanato de Bonito | true |
12   - And feature "products_for_enterprises" is enabled on environment
13   - And the following product_categories
14   - | name |
15   - | categ1 |
16   - | food |
17   - And I am on /catalog/artebonito
18   -
19   - Scenario: display titles
20   - Then the page title should be "Associação de Artesanato de Bonito"
21   - And I should see "Products/Services"
22   -
23   - Scenario: display the simplest possible product
24   - Given the following products
25   - | owner | category |
26   - | artebonito | categ1 |
27   - And I am on /catalog/artebonito
28   - Then I should see "categ1" within "li.product-link"
29   - And I should see "No image" within ".no-image"
30   - And I should not see "unit" within "#product-list"
31   - And I should not see "product unavailable"
32   - And I should not see "description"
33   - And I should not see "qualifiers"
34   - And I should not see "price composition"
35   -
36   - Scenario: display a simple product without price
37   - Given the following products
38   - | owner | category | name |
39   - | artebonito | categ1 | Produto1 |
40   - And I am on /catalog/artebonito
41   - Then I should see "Produto1" within "li.product-link"
42   - And I should see "No image" within ".no-image"
43   - And I should not see "unit" within "#product-list"
44   - And I should not see "product unavailable"
45   - And I should not see "description"
46   - And I should not see "qualifiers"
47   - And I should not see "price composition"
48   -
49   - Scenario: display a simple product without details
50   - Given the following products
51   - | owner | category | name | price |
52   - | artebonito | categ1 | Produto1 | 50.00 |
53   - And I am on /catalog/artebonito
54   - Then I should see "Produto1" within "li.product-link"
55   - And I should see "50.00" within "span.product-price"
56   - And I should see "unit" within "span.product-unit"
57   - And I should see "No image" within ".no-image"
58   - And I should not see "product unavailable"
59   - And I should not see "description"
60   - And I should not see "qualifiers"
61   - And I should not see "price composition"
62   -
63   - Scenario: don't display the price when it's $0.00
64   - Given the following products
65   - | owner | category | name | price |
66   - | artebonito | categ1 | Produto1 | 0.00 |
67   - And I am on /catalog/artebonito
68   - Then I should see "Produto1" within "li.product-link"
69   - And I should not see "0.00"
70   -
71   - Scenario: don't display the price when it's not defined
72   - Given the following products
73   - | owner | category | name |
74   - | artebonito | categ1 | Produto1 |
75   - And I am on /catalog/artebonito
76   - Then I should see "Produto1" within "li.product-link"
77   - And I should not see "0.00"
78   - And I should see "No image" within ".no-image"
79   - And I should not see "product unavailable"
80   - And I should not see "description"
81   - And I should not see "qualifiers"
82   - And I should not see "price composition"
83   -
84   - Scenario: product name links to product page
85   - Given the following products
86   - | owner | category | name | price |
87   - | artebonito | categ1 | Produto1 | 50.00 |
88   - And I am on /catalog/artebonito
89   - When I follow "Produto1" within "li.product-link"
90   - Then I should be taken to "Produto1" product page
91   -
92   - Scenario: display product with custom image
93   - Given the following products
94   - | owner | category | name | price | img |
95   - | artebonito | categ1 | Agrotox | 12.34 | agrotox |
96   - And I am on /catalog/artebonito
97   - Then I should see "Agrotox" within "li.product-link"
98   - And I should see "12.34" within "span.product-price"
99   - And I should see "unit" within "span.product-unit"
100   - And I should not see "No image"
101   - And I should not see "product unavailable"
102   - And I should not see "description"
103   - And I should not see "qualifiers"
104   - And I should not see "price composition"
105   -
106   - Scenario: display "zoom in" button
107   - Given the following products
108   - | owner | category | name | price | img |
109   - | artebonito | categ1 | Agrotox | 12.34 | agrotox |
110   - And I am on /catalog/artebonito
111   - And I should not see "No image"
112   - And I should see "Zoom in" within ".zoomify-image"
113   -
114   - Scenario: image links to product page
115   - Given the following products
116   - | owner | category | name | price | img |
117   - | artebonito | categ1 | Agrotox | 12.34 | agrotox |
118   - And I am on /catalog/artebonito
119   - When I follow "Agrotox" within ".product-image-link"
120   - Then I should be taken to "Agrotox" product page
121   -
122   - Scenario: display product with discount
123   - Given the following products
124   - | owner | category | name | price | discount | img |
125   - | artebonito | categ1 | Semterrinha | 99.99 | 12.34 | semterrinha |
126   - And I am on /catalog/artebonito
127   - Then I should see "Semterrinha" within "li.product-link"
128   - And I should see "99.99" within "span.product-discount"
129   - And I should see "87.65" within "span.product-price"
130   - And I should not see "No image"
131   - And I should not see "description"
132   - And I should not see "qualifiers"
133   - And I should not see "price composition"
134   -
135   - @selenium-fixme
136   - Scenario: display description button when needed (but not the description)
137   - Given the following products
138   - | owner | category | name | price | description |
139   - | artebonito | categ1 | Produto2 | 12.34 | A small description for a product that doesn't exist. |
140   - And I am on /catalog/artebonito
141   - And I reload and wait for the page
142   - Then I should see "Produto2" within "li.product-link"
143   - And I should see "12.34" within "span.product-price"
144   - And I should see "description" within "#product-description-button"
145   - And "description" should not be visible within "product-description-button"
146   - And I should see "A small description" within "#product-description"
147   - And "A small description for a product that doesn't exist" should not be visible within "product-description"
148   -
149   - @selenium-fixme
150   - Scenario: display description when button is clicked
151   - Given the following products
152   - | owner | category | name | price | description |
153   - | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
154   - And I am on /catalog/artebonito
155   - And I reload and wait for the page
156   - When I follow "product-description-button"
157   - Then I should see "A small description" within "#product-description"
158   - And "A small description for a product that doesn't exist" should not be visible within "product-description"
159   -
160   - @selenium-fixme
161   - Scenario: hide description
162   - Given the following products
163   - | owner | category | name | price | description |
164   - | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. |
165   - And I am on /catalog/artebonito
166   - And I reload and wait for the page
167   - When I click "product-description-button"
168   - Then I should see "A small description" within "#product-description"
169   - And the "product-description" should be visible
170   - When I click "product-list"
171   - Then the "product-description" should not be visible
172   -
173   - Scenario: display unavailable product
174   - Given the following products
175   - | owner | category | name | price | available |
176   - | artebonito | categ1 | Prod3 | 12.34 | false |
177   - And I am on /catalog/artebonito
178   - Then I should see "Prod3" within "li.not-available"
179   - And I should see "12.34" within "li.not-available"
180   - And I should see "product unavailable" within "li.product-unavailable"
181   - And I should not see "qualifiers"
182   - And I should not see "price composition"
183   -
184   - Scenario: display qualifiers
185   - Given the following qualifiers
186   - | name |
187   - | Organic |
188   - And the following certifiers
189   - | name | qualifiers |
190   - | Colivre | Organic |
191   - And the following products
192   - | owner | category | name | price | qualifier |
193   - | artebonito | categ1 | Banana | 0.99 | Organic |
194   - And I am on /catalog/artebonito
195   - Then I should see "Banana" within "li.product-link"
196   - And I should see "0.99" within "span.product-price"
197   - And I should see "qualifiers" within "li.product-qualifiers"
198   - And I should see "Organic" within "span.search-product-qualifier"
199   - And I should not see "price composition"
200   -
201   - @selenium-fixme
202   - Scenario: not display price composition button if price is not described
203   - Given the following product
204   - | owner | category | name | price |
205   - | artebonito | food | Bananada | 10.00 |
206   - And the following input
207   - | product | category | price_per_unit | amount_used |
208   - | Bananada | food | 0.99 | 5 |
209   - And I am on /catalog/artebonito
210   - And I reload and wait for the page
211   - Then I should see "Bananada" within "li.product-link"
212   - And I should see "10.00" within "span.product-price"
213   - And the "#product-price-composition-button" should not be visible
214   -
215   - @selenium-fixme
216   - Scenario: display price composition button (but not inputs)
217   - Given the following product
218   - | owner | category | name | price |
219   - | artebonito | food | Bananada | 10.00 |
220   - And the following input
221   - | product | category | price_per_unit | amount_used |
222   - | Bananada | food | 2.00 | 5 |
223   - And I am on /catalog/artebonito
224   - And I reload and wait for the page
225   - Then I should see "Bananada" within "li.product-link"
226   - And I should see "10.00" within "span.product-price"
227   - And I should see "price composition" within "#product-price-composition-button"
228   - And the "#product-price-composition-button" should be visible
229   - And I should see "food" within "#product-price-composition"
230   - And I should see "10.00" within "#product-price-composition"
231   -
232   - @selenium-fixme
233   - Scenario: display price composition when button is clicked
234   - Given the following product
235   - | owner | category | name | price |
236   - | artebonito | food | Bananada | 10.88 |
237   - And the following input
238   - | product | category | price_per_unit | amount_used |
239   - | Bananada | food | 2.72 | 4 |
240   - And I am on /catalog/artebonito
241   - And I reload and wait for the page
242   - When I click "#product-price-composition-button"
243   - Then the "#product-price-composition" should be visible
244   - And I should see "food" within "#product-price-composition"
245   - And I should see "10.88" within "#product-price-composition"
246   -
247   - @selenium-fixme
248   - Scenario: display inputs and raw materials button when not completely filled
249   - Given the following product
250   - | owner | category | name | price |
251   - | artebonito | food | Vitamina | 17.99 |
252   - And the following unit
253   - | name | plural |
254   - | Liter | Liters |
255   - And the following input
256   - | product | category |
257   - | Vitamina | food |
258   - And I am on /catalog/artebonito
259   - And I reload and wait for the page
260   - Then the "#inputs-button" should be visible
261   - And I should see "inputs and raw materials" within "#inputs-button"
262   -
263   - @selenium-fixme
264   - Scenario: display inputs and raw materials button
265   - Given the following product
266   - | owner | category | name | price |
267   - | artebonito | food | Vitamina | 17.99 |
268   - And the following unit
269   - | name | plural |
270   - | Liter | Liters |
271   - And the following input
272   - | product | category | price_per_unit | amount_used | unit |
273   - | Vitamina | food | 1.45 | 7 | Liter |
274   - And I am on /catalog/artebonito
275   - And I reload and wait for the page
276   - Then I should see "Vitamina" within "li.product-link"
277   - And I should see "17.99" within "span.product-price"
278   - And the "#inputs-button" should be visible
279   - And I should see "inputs and raw materials" within "#inputs-button"
280   - And the "#inputs-description" should not be visible
281   - And I should see "7.0 Liter of food" within "#inputs-description"
282   -
283   - @selenium-fixme
284   - Scenario: display inputs and raw materials description
285   - Given the following product
286   - | owner | category | name | price |
287   - | artebonito | food | Vitamina | 17.99 |
288   - And the following unit
289   - | name | plural |
290   - | Liter | Liters |
291   - And the following input
292   - | product | category | price_per_unit | amount_used | unit |
293   - | Vitamina | food | 1.45 | 7 | Liter |
294   - And I am on /catalog/artebonito
295   - And I reload and wait for the page
296   - When I click "#inputs-button"
297   - Then the "#inputs-description" should be visible
298   - And I should see "7.0 Liter of food" within "#inputs-description"
299   -
300   - @selenium-fixme
301   - Scenario: hide inputs and raw materials
302   - Given the following product
303   - | owner | category | name | price |
304   - | artebonito | food | Vitamina | 17.99 |
305   - And the following unit
306   - | name | plural |
307   - | Liter | Liters |
308   - And the following input
309   - | product | category | price_per_unit | amount_used | unit |
310   - | Vitamina | food | 1.45 | 7 | Liter |
311   - And I am on /catalog/artebonito
312   - And I reload and wait for the page
313   - When I click "#inputs-button"
314   - Then the "#inputs-description" should be visible
315   - And I should see "7.0 Liter of food" within "#inputs-description"
316   - When I click "#product-list"
317   - Then the "#inputs-description" should not be visible
features/categories_block.feature
... ... @@ -4,16 +4,6 @@ Feature: categories_block
4 4  
5 5 Background:
6 6 Given I am on the homepage
7   - And the following product_categories
8   - | name | display_in_menu |
9   - | Food | true |
10   - | Book | true |
11   - And the following product_categories
12   - | parent | name | display_in_menu |
13   - | Food | Vegetarian | true |
14   - | Food | Steak | true |
15   - | Book | Fiction | false |
16   - | Book | Literature | true |
17 7 And the following categories
18 8 | name | display_in_menu |
19 9 | Wood | true |
... ... @@ -27,49 +17,6 @@ Feature: categories_block
27 17 And I go to /admin/environment_design
28 18  
29 19 @selenium
30   - Scenario: List just product categories
31   - Given display ".button-bar"
32   - And I follow "Edit" within ".block-outer .categories-block"
33   - And I check "Product"
34   - When I press "Save"
35   - Then I should see "Food"
36   - And I should see "Book"
37   - And "Vegetarian" should not be visible within "span#category-name"
38   - And "Steak" should not be visible within "span#category-name"
39   - And "Fiction" should not be visible within "span#category-name"
40   -
41   - @selenium
42   - Scenario: Show submenu if it exists
43   - Given display ".button-bar"
44   - And I follow "Edit" within ".block-outer .categories-block"
45   - And I check "Product"
46   - And I press "Save"
47   - And I go to /
48   - Then I should see "Food"
49   - And I should see "Book"
50   - And "Vegetarian" should not be visible within "span#category-name"
51   - And "Steak" should not be visible within "span#category-name"
52   - And "Literature" should not be visible within "span#category-name"
53   - When I follow "block_2_category_2"
54   - Then I should see "Literature"
55   - When I follow "block_2_category_1"
56   - Then I should see "Vegetarian"
57   - And I should see "Steak"
58   - And I should not see "Fiction"
59   -
60   - @selenium
61   - Scenario: Show only one submenu per time
62   - Given display ".button-bar"
63   - And I follow "Edit" within ".block-outer .categories-block"
64   - And I check "Product"
65   - And I press "Save"
66   - And I go to /
67   - Then I should see "Book"
68   - And "Literature" should not be visible within "span#category-name"
69   - When I follow "block_2_category_2"
70   - Then I should see "Literature"
71   -
72   - @selenium
73 20 Scenario: List just general categories
74 21 Given display ".button-bar"
75 22 And I follow "Edit" within ".block-outer .categories-block"
... ...
features/enterprise_homepage.feature
... ... @@ -1,39 +0,0 @@
1   -# 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.
2   -
3   -Feature: enterprise homepage
4   - As a noosfero visitor
5   - I want to browse an enterprise's homepage
6   - In order to know more information about the enterprise
7   -
8   - Background:
9   - Given the following users
10   - | login | name |
11   - | durdentyler | Tyler Durden |
12   - And the following enterprises
13   - | identifier | owner | name | contact_email | contact_phone | enabled |
14   - | mayhem | durdentyler | Paper Street Soap Co. | queen@workerbees.org | (288) 555-0153 | true |
15   - And the following enterprise homepage
16   - | enterprise | name |
17   - | mayhem | article homepage |
18   - And the following product_category
19   - | name |
20   - | soap |
21   - And the following product
22   - | name | category | owner |
23   - | Natural Handmade | soap | mayhem |
24   - And feature "products_for_enterprises" is enabled on environment
25   -
26   -
27   - Scenario: display profile info
28   - When I go to /mayhem/homepage
29   - Then I should see "queen@workerbees.org"
30   - And I should see "(288) 555-0153"
31   -
32   - Scenario: display products list
33   - When I go to /mayhem/homepage
34   - Then I should see "Natural Handmade"
35   -
36   - Scenario: display link to product
37   - When I go to /mayhem/homepage
38   - And I follow "Natural Handmade"
39   - Then I should be taken to "Natural Handmade" product page
features/featured_products_block.feature
... ... @@ -1,47 +0,0 @@
1   -Feature: featured_products_block
2   - As a profile owner
3   - I want to edit the featured block
4   -
5   - Background:
6   - Given I am on the homepage
7   - And the following users
8   - | login | name |
9   - | eddievedder | Eddie Vedder |
10   - And the following enterprises
11   - | identifier | owner | name | enabled |
12   - | redemoinho | eddievedder | Rede Moinho | true |
13   - And the following blocks
14   - | owner | type |
15   - | redemoinho | FeaturedProductsBlock |
16   - And the following product_category
17   - | name |
18   - | automobile |
19   - And the following products
20   - | owner | category | name | description | highlighted |
21   - | redemoinho | automobile | Car | Red Car | true |
22   - | redemoinho | automobile | Truck | Blue Truck | true |
23   - | redemoinho | automobile | Moto | Very long description of and auto-mobile moto to be truncated | true |
24   - And I am logged in as "eddievedder"
25   -
26   - @selenium-fixme
27   - Scenario: select a product to be featured
28   - And I follow "Manage my groups"
29   - And I follow "Control panel of this group"
30   - And I follow "Edit sideboxes"
31   - Given I follow "Edit" within ".featured-products-block"
32   - And I select "Car"
33   - When I press "Save"
34   - Then I should see "Car"
35   - And I should not see "float_to_currency"
36   - And I should not see "product_path"
37   -
38   - @selenium-fixme
39   - Scenario: display block with long description
40   - Given I follow "Manage my groups"
41   - And I follow "Control panel of this group"
42   - And I follow "Edit sideboxes"
43   - And I follow "Edit" within ".featured-products-block"
44   - And I select "Moto"
45   - And I press "Save"
46   - When I am on redemoinho's homepage
47   - Then I should see "Very long description of and auto-mobile moto to b..."
features/search.feature
... ... @@ -3,9 +3,6 @@ Feature: search
3 3 I want to search
4 4 In order to find stuff
5 5  
6   - Background:
7   - Given feature "disable_asset_products" is disabled on environment
8   -
9 6 Scenario: show empty results in all enabled assets
10 7 Given I go to the search page
11 8 And I fill in "search-input" with "Anything"
... ... @@ -18,8 +15,6 @@ Feature: search
18 15 And I should see "None" within ".search-results-enterprises"
19 16 And I should see "Contents" within ".search-results-articles"
20 17 And I should see "None" within ".search-results-articles"
21   - And I should see "Products" within ".search-results-products"
22   - And I should see "None" within ".search-results-products"
23 18 And I should see "Events" within ".search-results-events"
24 19 And I should see "None" within ".search-results-events"
25 20  
... ... @@ -92,23 +87,6 @@ Feature: search
92 87 Then I should see "whales and dolphins" within "div.search-results-articles"
93 88 And I should not see "bees and butterflies"
94 89  
95   - Scenario: simple search for product
96   - Given the following enterprises
97   - | identifier | name |
98   - | colivre-ent | Colivre |
99   - And the following product_categories
100   - | name |
101   - | Development |
102   - And the following products
103   - | owner | category | name |
104   - | colivre-ent | development | social networks consultancy |
105   - | colivre-ent | development | wikis consultancy |
106   - When I go to the search page
107   - And I fill in "search-input" with "wikis"
108   - And I press "Search"
109   - Then I should see "wikis consultancy" within "div.search-results-products"
110   - And I should not see "social networks consultancy"
111   -
112 90 Scenario: simple search for event
113 91 Given the following communities
114 92 | identifier | name |
... ... @@ -130,15 +108,8 @@ Feature: search
130 108 And the following communities
131 109 | identifier | name |
132 110 | noosfero-users | Noosfero users |
133   - And the following product_categories
134   - | name |
135   - | Development |
136   - And the following products
137   - | owner | name | category |
138   - | colivre_dev | Noosfero platform | Development |
139 111 When I go to the search page
140 112 And I fill in "search-input" with "noosfero"
141 113 And I press "Search"
142 114 Then I should see "Colivre - Noosfero dev." within "div.search-results-enterprises"
143 115 And I should see "Noosfero users" within "div.search-results-communities"
144   - And I should see "Noosfero platform" within "div.search-results-products"
... ...
features/search_products.feature
... ... @@ -1,105 +0,0 @@
1   -Feature: search products
2   - As a noosfero user
3   - I want to search products
4   - In order to find ones that interest me
5   -
6   - Background:
7   - Given feature "disable_asset_products" is disabled on environment
8   - And the following enterprises
9   - | identifier | name |
10   - | colivre-ent | Colivre |
11   - And the following product_categories
12   - | name |
13   - | Development |
14   - And the following products
15   - | owner | category | name | price | img |
16   - | colivre-ent | development | social networks consultancy | 1.00 | fruits |
17   - | colivre-ent | development | wikis consultancy | 2.00 | shoes |
18   -
19   - Scenario: show recent products on index
20   - When I go to the search products page
21   - Then I should see "wikis consultancy" within "#search-results"
22   - And I should see "social networks consultancy" within "#search-results"
23   -
24   - Scenario: show empty search results
25   - When I search products for "something unrelated"
26   - Then I should see "None" within ".search-results-type-empty"
27   -
28   - Scenario: simple search for product
29   - Given there are no pending jobs
30   - When I search products for "wikis"
31   - Then I should see "wikis consultancy" within "#search-results"
32   - And I should see "wikis consultancy" within ".only-one-result-box"
33   - And I should see wikis consultancy's product image
34   - And I should not see "social networks consultancy"
35   - And I should not see social networks consultancy's product image
36   -
37   - Scenario: show percentage (100%) of solidary economy inputs in results
38   - Given the following inputs
39   - | product | category | solidary |
40   - | wikis consultancy | development | true |
41   - When I go to the search products page
42   - And I fill in "search-input" with "wikis"
43   - And I press "Search"
44   - Then I should see "100%" within "div.search-product-ecosol-percentage-icon-100"
45   -
46   - Scenario: show percentage (50%) of solidary economy inputs in results
47   - Given the following inputs
48   - | product | category | solidary |
49   - | wikis consultancy | development | true |
50   - | wikis consultancy | development | false |
51   - When I go to the search products page
52   - And I fill in "search-input" with "wikis"
53   - And I press "Search"
54   - Then I should see "50%" within "div.search-product-ecosol-percentage-icon-50"
55   -
56   - Scenario: show percentage (75%) of solidary economy inputs in results
57   - Given the following inputs
58   - | product | category | solidary |
59   - | wikis consultancy | development | true |
60   - | wikis consultancy | development | true |
61   - | wikis consultancy | development | true |
62   - | wikis consultancy | development | false |
63   - When I go to the search products page
64   - And I fill in "search-input" with "wikis"
65   - And I press "Search"
66   - Then I should see "75%" within "div.search-product-ecosol-percentage-icon-75"
67   -
68   - Scenario: show percentage (25%) of solidary economy inputs in results
69   - Given the following inputs
70   - | product | category | solidary |
71   - | wikis consultancy | development | true |
72   - | wikis consultancy | development | false |
73   - | wikis consultancy | development | false |
74   - | wikis consultancy | development | false |
75   - When I go to the search products page
76   - And I fill in "search-input" with "wikis"
77   - And I press "Search"
78   - Then I should see "25%" within "div.search-product-ecosol-percentage-icon-25"
79   -
80   - Scenario: display "zoom in" button on images on results
81   - Given the following products
82   - | owner | category | name | price | img |
83   - | colivre-ent | development | noosfero | 12.34 | noosfero-network |
84   - When I go to the search products page
85   - And I fill in "search-input" with "noosfero"
86   - And I press "Search"
87   - Then I should not see "No image"
88   - And I should see "Zoom in" within "a.zoomify-image"
89   -
90   - Scenario: find products without exact query
91   - Given the following product_category
92   - | name |
93   - | Software Livre |
94   - And the following products
95   - | owner | name | category |
96   - | colivre-ent | Noosfero Social Network Platform | software-livre |
97   - When I go to the search products page
98   - And I fill in "search-input" with "Noosfero Social"
99   - And I press "Search"
100   - Then I should see "Noosfero Social Network Platform" within "#search-results"
101   -
102   - Scenario: don't search when products are disabled in environment
103   - Given feature "disable_asset_products" is enabled on environment
104   - When I go to the search products page
105   - Then I should see "There is no such page" within "#not-found"