Commit 2ae57e721398479198b0b97a9bdae1802672cf30
Exists in
master
and in
29 other branches
Merge branch 'master' into rails-2.3.5
Conflicts: features/step_definitions/noosfero_steps.rb
Showing
78 changed files
with
2512 additions
and
374 deletions
Show diff stats
app/controllers/my_profile/manage_products_controller.rb
... | ... | @@ -111,6 +111,36 @@ class ManageProductsController < ApplicationController |
111 | 111 | end |
112 | 112 | end |
113 | 113 | |
114 | + def manage_product_details | |
115 | + @product = @profile.products.find(params[:id]) | |
116 | + if request.post? | |
117 | + @product.update_price_details(params[:price_details]) if params[:price_details] | |
118 | + render :partial => 'display_price_details' | |
119 | + else | |
120 | + render :partial => 'manage_product_details' | |
121 | + end | |
122 | + end | |
123 | + | |
124 | + def remove_price_detail | |
125 | + @product = @profile.products.find(params[:product]) | |
126 | + @price_detail = @product.price_details.find(params[:id]) | |
127 | + @product = @price_detail.product | |
128 | + if request.post? | |
129 | + @price_detail.destroy | |
130 | + render :nothing => true | |
131 | + end | |
132 | + end | |
133 | + | |
134 | + def display_price_composition_bar | |
135 | + @product = @profile.products.find(params[:id]) | |
136 | + render :partial => 'price_composition_bar' | |
137 | + end | |
138 | + | |
139 | + def display_inputs_cost | |
140 | + @product = @profile.products.find(params[:id]) | |
141 | + render :inline => "<%= float_to_currency(@product.inputs_cost) %>" | |
142 | + end | |
143 | + | |
114 | 144 | def destroy |
115 | 145 | @product = @profile.products.find(params[:id]) |
116 | 146 | if @product.destroy |
... | ... | @@ -167,4 +197,18 @@ class ManageProductsController < ApplicationController |
167 | 197 | end |
168 | 198 | end |
169 | 199 | |
200 | + def create_production_cost | |
201 | + cost = @profile.production_costs.create(:name => params[:id]) | |
202 | + if cost.valid? | |
203 | + cost.save | |
204 | + render :text => {:name => cost.name, | |
205 | + :id => cost.id, | |
206 | + :ok => true | |
207 | + }.to_json | |
208 | + else | |
209 | + render :text => {:ok => false, | |
210 | + :error_msg => _(cost.errors['name']) % {:fn => _('Name')} | |
211 | + }.to_json | |
212 | + end | |
213 | + end | |
170 | 214 | end | ... | ... |
app/controllers/public/catalog_controller.rb
... | ... | @@ -4,10 +4,11 @@ class CatalogController < PublicController |
4 | 4 | before_filter :check_enterprise_and_environment |
5 | 5 | |
6 | 6 | def index |
7 | - @products = @profile.products.paginate(:per_page => 10, :page => params[:page]) | |
7 | + @products = @profile.products.paginate(:order => 'name asc', :per_page => 9, :page => params[:page]) | |
8 | 8 | end |
9 | 9 | |
10 | 10 | protected |
11 | + | |
11 | 12 | def check_enterprise_and_environment |
12 | 13 | unless @profile.kind_of?(Enterprise) && !@profile.environment.enabled?('disable_products_for_enterprises') |
13 | 14 | redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -1254,25 +1254,27 @@ module ApplicationHelper |
1254 | 1254 | task.information[:message] % values |
1255 | 1255 | end |
1256 | 1256 | |
1257 | + def add_zoom_to_article_images | |
1258 | + add_zoom_to_images if environment.enabled?(:show_zoom_button_on_article_images) | |
1259 | + end | |
1260 | + | |
1257 | 1261 | def add_zoom_to_images |
1258 | - if environment.enabled?(:show_zoom_button_on_article_images) | |
1259 | - stylesheet_link_tag('fancybox') + | |
1260 | - javascript_include_tag('jquery.fancybox-1.3.4.pack') + | |
1261 | - javascript_tag("jQuery(function($) { | |
1262 | - $(window).load( function() { | |
1263 | - $('#article .article-body img').each( function(index) { | |
1264 | - var original = original_image_dimensions($(this).attr('src')); | |
1265 | - if ($(this).width() < original['width'] || $(this).height() < original['height']) { | |
1266 | - $(this).wrap('<div class=\"zoomable-image\" />'); | |
1267 | - $(this).parent('.zoomable-image').attr('style', $(this).attr('style')); | |
1268 | - $(this).attr('style', ''); | |
1269 | - $(this).after(\'<a href=\"' + $(this).attr('src') + '\" class=\"zoomify-image\"><span class=\"zoomify-text\">%s</span></a>'); | |
1270 | - } | |
1271 | - }); | |
1272 | - $('.zoomify-image').fancybox(); | |
1262 | + stylesheet_link_tag('fancybox') + | |
1263 | + javascript_include_tag('jquery.fancybox-1.3.4.pack') + | |
1264 | + javascript_tag("jQuery(function($) { | |
1265 | + $(window).load( function() { | |
1266 | + $('#article .article-body img').each( function(index) { | |
1267 | + var original = original_image_dimensions($(this).attr('src')); | |
1268 | + if ($(this).width() < original['width'] || $(this).height() < original['height']) { | |
1269 | + $(this).wrap('<div class=\"zoomable-image\" />'); | |
1270 | + $(this).parent('.zoomable-image').attr('style', $(this).attr('style')); | |
1271 | + $(this).attr('style', ''); | |
1272 | + $(this).after(\'<a href=\"' + $(this).attr('src') + '\" class=\"zoomify-image\"><span class=\"zoomify-text\">%s</span></a>'); | |
1273 | + } | |
1273 | 1274 | }); |
1274 | - });" % _('Zoom in')) | |
1275 | - end | |
1275 | + $('.zoomify-image').fancybox(); | |
1276 | + }); | |
1277 | + });" % _('Zoom in')) | |
1276 | 1278 | end |
1277 | 1279 | |
1278 | 1280 | def render_dialog_error_messages(instance_name) | ... | ... |
app/helpers/catalog_helper.rb
1 | 1 | module CatalogHelper |
2 | 2 | |
3 | -include DisplayHelper | |
4 | -include ManageProductsHelper | |
3 | + include DisplayHelper | |
4 | + include ManageProductsHelper | |
5 | 5 | |
6 | - def display_products_list(profile, products) | |
7 | - data = '' | |
8 | - extra_content = [] | |
9 | - extra_content_list = [] | |
10 | - products.each { |product| | |
11 | - extra_content = @plugins.map(:catalog_item_extras, product).collect { |content| instance_eval(&content) } if @plugins | |
12 | - extra_content_list = @plugins.map(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } if @plugins | |
13 | - data << content_tag('li', | |
14 | - link_to_product(product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:portrait) ) + | |
15 | - content_tag('h3', link_to_product(product)) + | |
16 | - content_tag('ul', | |
17 | - (product.price ? content_tag('li', _('Price: %s') % ( "%.2f" % product.price), :class => 'product_price') : '') + | |
18 | - content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category') + | |
19 | - extra_content_list.map { |content| content_tag('li', content)}.join("\n") | |
20 | - ) + | |
21 | - (product.description ? content_tag('div', | |
22 | - txt2html(product.description), | |
23 | - :class => 'description') : tag('br', | |
24 | - :style => 'clear:both')) + | |
25 | - extra_content.join("\n"), | |
26 | - :class => 'product') | |
27 | - } | |
28 | - content_tag('h1', _('Products/Services')) + content_tag('ul', data, :id => 'product_list') | |
29 | - end | |
30 | - | |
31 | - private | |
32 | - | |
33 | - def product_category_name(profile, product_category) | |
34 | - if profile.enabled? | |
35 | - link_to_product_category(product_category) | |
36 | - else | |
37 | - product_category ? product_category.full_name(' → ') : _('Uncategorized product') | |
38 | - end | |
39 | - end | |
40 | 6 | end | ... | ... |
app/helpers/display_helper.rb
... | ... | @@ -8,6 +8,20 @@ module DisplayHelper |
8 | 8 | opts |
9 | 9 | end |
10 | 10 | |
11 | + def image_link_to_product(product, opts={}) | |
12 | + return _('No product') unless product | |
13 | + target = product_path(product) | |
14 | + link_to image_tag(product.default_image(:big), :alt => product.name), | |
15 | + target, | |
16 | + opts | |
17 | + end | |
18 | + | |
19 | + def price_span(price, options = {}) | |
20 | + content_tag 'span', | |
21 | + number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator), | |
22 | + options | |
23 | + end | |
24 | + | |
11 | 25 | def product_path(product) |
12 | 26 | product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url |
13 | 27 | end | ... | ... |
app/helpers/manage_products_helper.rb
... | ... | @@ -271,4 +271,23 @@ module ManageProductsHelper |
271 | 271 | return input_amount_used if input.unit.blank? |
272 | 272 | 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') } |
273 | 273 | end |
274 | + | |
275 | + def select_production_cost(product,selected=nil) | |
276 | + url = url_for( :controller => 'manage_products', :action => 'create_production_cost' ) | |
277 | + prompt_msg = _('Insert the name of the new cost:') | |
278 | + error_msg = _('Something went wrong. Please, try again') | |
279 | + select_tag('price_details[][production_cost_id]', | |
280 | + '<option value="" disabled="disabled">' + _('Select...') + '</option>' + | |
281 | + options_for_select(product.available_production_costs.map {|item| [truncate(item.name, 10, '...'), item.id]} + [[_('Other cost'), '']], selected), | |
282 | + {:class => 'production-cost-selection', | |
283 | + :onchange => "productionCostTypeChange(this, '#{url}', '#{prompt_msg}', '#{error_msg}')"}) | |
284 | + end | |
285 | + | |
286 | + def price_composition_progressbar_text(product, args = {}) | |
287 | + currency = environment.currency_unit | |
288 | + production_cost = args[:production_cost_value] || product.formatted_value(:total_production_cost) | |
289 | + product_price = args[:product_price] || product.formatted_value(:price) | |
290 | + | |
291 | + _("%{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')} | |
292 | + end | |
274 | 293 | end | ... | ... |
app/models/enterprise.rb
... | ... | @@ -6,6 +6,7 @@ class Enterprise < Organization |
6 | 6 | |
7 | 7 | has_many :products, :dependent => :destroy, :order => 'name ASC' |
8 | 8 | has_many :inputs, :through => :products |
9 | + has_many :production_costs, :as => :owner | |
9 | 10 | |
10 | 11 | has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people' |
11 | 12 | ... | ... |
app/models/enterprise_homepage.rb
... | ... | @@ -12,18 +12,13 @@ class EnterpriseHomepage < Article |
12 | 12 | profile.nil? ? _('Homepage') : profile.name |
13 | 13 | end |
14 | 14 | |
15 | - # FIXME isn't this too much including just to be able to generate some HTML? | |
16 | - include ActionView::Helpers::TagHelper | |
17 | - include ActionView::Helpers::UrlHelper | |
18 | - include ActionController::UrlWriter | |
19 | - include ActionView::Helpers::AssetTagHelper | |
20 | - include EnterpriseHomepageHelper | |
21 | - include CatalogHelper | |
22 | - | |
23 | - def to_html(options ={}) | |
24 | - products = self.profile.products | |
25 | - display_profile_info(self.profile) + content_tag('div', self.body || '') + | |
26 | - (self.profile.environment.enabled?('disable_products_for_enterprises') ? '' : display_products_list(self.profile, products)) | |
15 | + def to_html(options = {}) | |
16 | + enterprise_homepage = self | |
17 | + lambda do | |
18 | + extend EnterpriseHomepageHelper | |
19 | + @products = profile.products.paginate(:order => 'id asc', :per_page => 9, :page => 1) | |
20 | + render :partial => 'content_viewer/enterprise_homepage', :object => enterprise_homepage | |
21 | + end | |
27 | 22 | end |
28 | 23 | |
29 | 24 | def can_display_hits? | ... | ... |
app/models/environment.rb
app/models/image.rb
... | ... | @@ -9,15 +9,15 @@ class Image < ActiveRecord::Base |
9 | 9 | has_attachment :content_type => :image, |
10 | 10 | :storage => :file_system, |
11 | 11 | :path_prefix => 'public/image_uploads', |
12 | - :resize_to => '320x200>', | |
12 | + :resize_to => '800x600>', | |
13 | 13 | :thumbnails => { :big => '150x150', |
14 | 14 | :thumb => '100x100', |
15 | 15 | :portrait => '64x64', |
16 | 16 | :minor => '50x50', |
17 | 17 | :icon => '20x20!' }, |
18 | - :max_size => 500.kilobytes # remember to update validate message below | |
18 | + :max_size => 5.megabytes # remember to update validate message below | |
19 | 19 | |
20 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 500.0 KB") | |
20 | + validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB") | |
21 | 21 | |
22 | 22 | delay_attachment_fu_thumbnails |
23 | 23 | ... | ... |
app/models/input.rb
... | ... | @@ -45,6 +45,18 @@ class Input < ActiveRecord::Base |
45 | 45 | %w[price_per_unit amount_used].each do |field| |
46 | 46 | return true unless self.send(field).blank? |
47 | 47 | end |
48 | - return false | |
48 | + false | |
49 | + end | |
50 | + | |
51 | + def has_all_price_details? | |
52 | + %w[price_per_unit unit amount_used].each do |field| | |
53 | + return false if self.send(field).blank? | |
54 | + end | |
55 | + true | |
56 | + end | |
57 | + | |
58 | + def cost | |
59 | + return 0 if self.amount_used.blank? || self.price_per_unit.blank? | |
60 | + self.amount_used * self.price_per_unit | |
49 | 61 | end |
50 | 62 | end | ... | ... |
... | ... | @@ -0,0 +1,27 @@ |
1 | +class PriceDetail < ActiveRecord::Base | |
2 | + | |
3 | + belongs_to :product | |
4 | + validates_presence_of :product_id | |
5 | + | |
6 | + belongs_to :production_cost | |
7 | + validates_presence_of :production_cost_id | |
8 | + validates_uniqueness_of :production_cost_id, :scope => :product_id | |
9 | + | |
10 | + def price | |
11 | + self[:price] || 0 | |
12 | + end | |
13 | + | |
14 | + include FloatHelper | |
15 | + def price=(value) | |
16 | + if value.is_a?(String) | |
17 | + super(decimal_to_float(value)) | |
18 | + else | |
19 | + super(value) | |
20 | + end | |
21 | + end | |
22 | + | |
23 | + def formatted_value(value) | |
24 | + ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value] | |
25 | + end | |
26 | + | |
27 | +end | ... | ... |
app/models/product.rb
... | ... | @@ -5,6 +5,8 @@ class Product < ActiveRecord::Base |
5 | 5 | has_many :product_qualifiers |
6 | 6 | has_many :qualifiers, :through => :product_qualifiers |
7 | 7 | has_many :inputs, :dependent => :destroy, :order => 'position' |
8 | + has_many :price_details, :dependent => :destroy | |
9 | + has_many :production_costs, :through => :price_details | |
8 | 10 | |
9 | 11 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true |
10 | 12 | validates_presence_of :product_category_id |
... | ... | @@ -101,12 +103,13 @@ class Product < ActiveRecord::Base |
101 | 103 | enterprise.public_profile |
102 | 104 | end |
103 | 105 | |
104 | - def formatted_value(value) | |
105 | - ("%.2f" % self[value]).to_s.gsub('.', enterprise.environment.currency_separator) if self[value] | |
106 | + def formatted_value(method) | |
107 | + value = self[method] || self.send(method) | |
108 | + ("%.2f" % value).to_s.gsub('.', enterprise.environment.currency_separator) if value | |
106 | 109 | end |
107 | 110 | |
108 | 111 | def price_with_discount |
109 | - price - discount if discount | |
112 | + discount ? (price - discount) : price | |
110 | 113 | end |
111 | 114 | |
112 | 115 | def price=(value) |
... | ... | @@ -125,6 +128,23 @@ class Product < ActiveRecord::Base |
125 | 128 | end |
126 | 129 | end |
127 | 130 | |
131 | + # Note: will probably be completely overhauled for AI1413 | |
132 | + def inputs_prices? | |
133 | + return false if self.inputs.count <= 0 | |
134 | + self.inputs.each do |input| | |
135 | + return false if input.has_price_details? == false | |
136 | + end | |
137 | + true | |
138 | + end | |
139 | + | |
140 | + def any_inputs_details? | |
141 | + return false if self.inputs.count <= 0 | |
142 | + self.inputs.each do |input| | |
143 | + return true if input.has_all_price_details? == true | |
144 | + end | |
145 | + false | |
146 | + end | |
147 | + | |
128 | 148 | def has_basic_info? |
129 | 149 | %w[unit price discount].each do |field| |
130 | 150 | return true if !self.send(field).blank? |
... | ... | @@ -153,4 +173,43 @@ class Product < ActiveRecord::Base |
153 | 173 | true |
154 | 174 | end |
155 | 175 | |
176 | + def inputs_cost | |
177 | + return 0 if inputs.empty? | |
178 | + inputs.map(&:cost).inject { |sum,price| sum + price } | |
179 | + end | |
180 | + | |
181 | + def total_production_cost | |
182 | + return inputs_cost if price_details.empty? | |
183 | + inputs_cost + price_details.map(&:price).inject { |sum,price| sum + price } | |
184 | + end | |
185 | + | |
186 | + def price_described? | |
187 | + return false if price.nil? | |
188 | + (price - total_production_cost).zero? | |
189 | + end | |
190 | + | |
191 | + def update_price_details(price_details) | |
192 | + self.price_details.destroy_all | |
193 | + price_details.each do |price_detail| | |
194 | + self.price_details.create(price_detail) | |
195 | + end | |
196 | + end | |
197 | + | |
198 | + def price_description_percentage | |
199 | + total_production_cost * 100 / price | |
200 | + end | |
201 | + | |
202 | + def available_production_costs | |
203 | + self.enterprise.environment.production_costs + self.enterprise.production_costs | |
204 | + end | |
205 | + | |
206 | + include ActionController::UrlWriter | |
207 | + def price_composition_bar_display_url | |
208 | + url_for({:host => enterprise.default_hostname, :controller => 'manage_products', :action => 'display_price_composition_bar', :profile => enterprise.identifier, :id => self.id }.merge(Noosfero.url_options)) | |
209 | + end | |
210 | + | |
211 | + def inputs_cost_update_url | |
212 | + url_for({:host => enterprise.default_hostname, :controller => 'manage_products', :action => 'display_inputs_cost', :profile => enterprise.identifier, :id => self.id }.merge(Noosfero.url_options)) | |
213 | + end | |
214 | + | |
156 | 215 | end | ... | ... |
... | ... | @@ -0,0 +1,8 @@ |
1 | +class ProductionCost < ActiveRecord::Base | |
2 | + | |
3 | + belongs_to :owner, :polymorphic => true | |
4 | + validates_presence_of :owner | |
5 | + validates_presence_of :name | |
6 | + validates_length_of :name, :maximum => 30, :allow_blank => true | |
7 | + validates_uniqueness_of :name, :scope => [:owner_id, :owner_type] | |
8 | +end | ... | ... |
app/views/catalog/index.rhtml
1 | -<%= display_products_list @profile, @products %> | |
1 | +<% extra_content = [] %> | |
2 | +<% extra_content_list = [] %> | |
2 | 3 | |
3 | -<%= pagination_links @products %> | |
4 | +<ul id="product-list"> | |
5 | + <li><h1><%= _('Products/Services') %></h1></li> | |
6 | + | |
7 | + <% @products.each do |product| %> | |
8 | + <% extra_content = @plugins.map(:catalog_item_extras, product).collect { |content| instance_eval(&content) } %> | |
9 | + <% extra_content_list = @plugins.map(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } %> | |
10 | + | |
11 | + <li class="product <%= "not-available" unless product.available %>"> | |
12 | + <ul> | |
13 | + <li class="product-image-link"> | |
14 | + <% if product.image %> | |
15 | + <div class="zoomable-image"> | |
16 | + <%= link_to_product product, :class => 'product-big', :style => "background-image: url(#{product.default_image(:big)})" %> | |
17 | + <%= link_to content_tag(:span, _('Zoom in')), product.default_image(:big).gsub('_big',''), :class => 'zoomify-image' %> | |
18 | + </div> | |
19 | + <% else %> | |
20 | + <div class="no-image"><%= _('No image') %></div> | |
21 | + <% end %> | |
22 | + <div class="catalog-item-extras"><%= extra_content.join("\n") %></div> | |
23 | + </li> | |
24 | + | |
25 | + <li class="product-link"><%= link_to_product product %></li> | |
26 | + | |
27 | + <li class="product-price-line"> | |
28 | + <% unless product.discount.blank? or product.discount == 0 %> | |
29 | + <span class="product-discount"> | |
30 | + <span><%= _('from ') + price_span(product.price) %></span> | |
31 | + <span class="product-discount-by"><%= _('by ') %></span> | |
32 | + </span> | |
33 | + <% end %> | |
34 | + <% unless product.price.blank? or product.price == 0 %> | |
35 | + <span class="product-price"> | |
36 | + <%= price_span product.price_with_discount, :class => "product-price #{'with-discount' unless product.discount}" %> | |
37 | + <span class="product-unit"><%= _(' / ') + (product.unit ? product.unit.singular : _('unit')) %></span> | |
38 | + </span> | |
39 | + <% end %> | |
40 | + <div style="clear: both"></div> | |
41 | + </li> | |
42 | + | |
43 | + <% if product.description %> | |
44 | + <li class="product-description expand-box"> | |
45 | + <span id="product-description-button"><%= _('description') %></span> | |
46 | + <div> | |
47 | + <div class="arrow"></div> | |
48 | + <div class="content" id="product-description"><%= txt2html(product.description || '') %></div> | |
49 | + </div> | |
50 | + </li> | |
51 | + <% end %> | |
52 | + | |
53 | + <% if product.price_described? %> | |
54 | + <li class="product-price-composition expand-box"> | |
55 | + <span id="product-price-composition-button"><%= _('price composition') %></span> | |
56 | + <div> | |
57 | + <div class="arrow"></div> | |
58 | + <div class="content" id="product-price-composition"> | |
59 | + <% product.inputs.each do |i| %> | |
60 | + <div class="search-product-input-dots-to-price"> | |
61 | + <div class="search-product-input-name"><%= i.product_category.name %></div> | |
62 | + <%= price_span i.cost, :class => 'search-product-input-price' %> | |
63 | + </div> | |
64 | + <% end %> | |
65 | + <% product.price_details.each do |i| %> | |
66 | + <div class="search-product-input-dots-to-price"> | |
67 | + <div class="search-product-input-name"><%= i.production_cost.name %></div> | |
68 | + <%= price_span i.price, :class => 'search-product-input-price' %> | |
69 | + </div> | |
70 | + <% end %> | |
71 | + </div> | |
72 | + </div> | |
73 | + </li> | |
74 | + <% end %> | |
75 | + | |
76 | + <% if product.inputs.count > 0 %> | |
77 | + <li class="product-inputs expand-box"> | |
78 | + <span id="inputs-button"><%= _('inputs and raw materials') %></span> | |
79 | + <div> | |
80 | + <div class="arrow"></div> | |
81 | + <div class="content" id="inputs-description"> | |
82 | + <% product.inputs.each do |i| %> | |
83 | + <div> | |
84 | + <%= _('%{amount_used} %{unit} of') % {:amount_used => i.amount_used, :unit => i.unit.singular} + ' ' if i.has_all_price_details? %> | |
85 | + <%= i.product_category.name %> | |
86 | + </div> | |
87 | + <% end %> | |
88 | + </div> | |
89 | + </div> | |
90 | + </li> | |
91 | + <% end %> | |
92 | + | |
93 | + <% unless product.qualifiers.blank? %> | |
94 | + <li class="product-qualifiers"> | |
95 | + <span><%= _('qualifiers') if product.product_qualifiers.count > 0 %></span> | |
96 | + <div><%= render :partial => 'shared/product/qualifiers', :locals => {:product => product} %></div> | |
97 | + <% end %> | |
98 | + | |
99 | + <% extra_content_list.map do |content| %> | |
100 | + <li class="catalog-list-item-extras"><%= content %></li> | |
101 | + <% end %> | |
102 | + | |
103 | + <li class="product-unavailable"><%= _('product unavailable') unless product.available %></li> | |
104 | + </ul> | |
105 | + </li> | |
106 | + <% end %> | |
107 | +</ul> | |
108 | + | |
109 | +<%= pagination_links @products, :params => {:controller => :catalog, :action => :index, :profile => profile.identifier} %> | |
110 | + | |
111 | +<%= add_zoom_to_images %> | |
112 | + | |
113 | +<br style="clear:both"/> | ... | ... |
app/views/content_viewer/view_page.rhtml
app/views/layouts/_javascript.rhtml
1 | -<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery.cookie', 'reflection', 'add-and-join', 'jquery.tokeninput', 'report-abuse','colorbox', 'jquery-validation/jquery.validate', :cache => 'cache-general' %> | |
1 | +<%= javascript_include_tag :defaults, 'jquery-latest.js', 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery.cookie', 'reflection', 'add-and-join', 'jquery.tokeninput', 'report-abuse','colorbox', 'jquery-validation/jquery.validate', 'catalog', 'manage-products', :cache => 'cache-general' %> | |
2 | 2 | <% language = FastGettext.locale %> |
3 | 3 | <%= javascript_include_tag 'jquery-validation/localization/messages_'+language, 'jquery-validation/localization/methods_'+language %> | ... | ... |
app/views/layouts/application-ng.rhtml
... | ... | @@ -11,13 +11,13 @@ |
11 | 11 | <%= stylesheet_link_tag noosfero_stylesheets, :cache => 'cache' %> |
12 | 12 | <%= stylesheet_link_tag template_stylesheet_path %> |
13 | 13 | <%= stylesheet_link_tag icon_theme_stylesheet_path %> |
14 | - <%= stylesheet_link_tag theme_stylesheet_path %> | |
15 | 14 | <%= stylesheet_link_tag jquery_ui_theme_stylesheet_path %> |
16 | 15 | <% @plugins.enabled_plugins.each do |plugin| %> |
17 | 16 | <% if plugin.stylesheet? %> |
18 | 17 | <%= stylesheet_tag plugin.class.public_path('style.css'), {} %> |
19 | 18 | <% end %> |
20 | 19 | <% end %> |
20 | + <%= stylesheet_link_tag theme_stylesheet_path %> | |
21 | 21 | |
22 | 22 | <%# Add custom tags/styles/etc via content_for %> |
23 | 23 | <%= yield :head %> |
... | ... | @@ -30,7 +30,7 @@ |
30 | 30 | <%= |
31 | 31 | @plugins.map(:head_ending).collect do |content| |
32 | 32 | content.respond_to?(:call) ? content.call : content |
33 | - end.join('\n') | |
33 | + end.join("\n") | |
34 | 34 | %> |
35 | 35 | </head> |
36 | 36 | <body class="<%= |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | <%= |
46 | 46 | @plugins.map(:body_beginning).collect do |content| |
47 | 47 | content.respond_to?(:call) ? content.call : content |
48 | - end.join('\n') | |
48 | + end.join("\n") | |
49 | 49 | %> |
50 | 50 | |
51 | 51 | <div id="wrap-1"> | ... | ... |
app/views/layouts/application.rhtml
... | ... | @@ -27,11 +27,8 @@ |
27 | 27 | <%# Add custom tags/styles/etc via content_for %> |
28 | 28 | <%= yield :head %> |
29 | 29 | <%= javascript_tag('render_all_jquery_ui_widgets()') %> |
30 | - <script type="text/javascript"> | |
31 | - jQuery(".numbers-only").keypress(function(event) { | |
32 | - return numbersonly(event, '<%= environment.currency_separator %>') | |
33 | - }); | |
34 | - </script> | |
30 | + | |
31 | + <%= render :partial => 'shared/numbers_only_javascript' %> | |
35 | 32 | </head> |
36 | 33 | |
37 | 34 | <body class='noosfero category<%= category_color %><%= | ... | ... |
... | ... | @@ -0,0 +1,18 @@ |
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.production_cost.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_info.rhtml
... | ... | @@ -49,15 +49,12 @@ |
49 | 49 | <%= hidden_field_tag "product[qualifiers_list]" %> |
50 | 50 | <% end %> |
51 | 51 | |
52 | + <%= hidden_field_tag 'info-bar-update-url', @product.price_composition_bar_display_url, :class => 'bar-update-url' %> | |
53 | + | |
52 | 54 | <% button_bar do %> |
53 | 55 | <%= submit_button :save, _('Save') %> |
54 | 56 | <%= cancel_edit_product_link(@product, 'info') %> |
55 | 57 | <% end %> |
56 | 58 | <% end %> |
57 | 59 | |
58 | -<% javascript_tag do %> | |
59 | - jQuery(".numbers-only").keypress(function(event) { | |
60 | - var separator = "<%= environment.currency_separator %>" | |
61 | - return numbersonly(event, separator) | |
62 | - }); | |
63 | -<% end %> | |
60 | +<%= render :partial => 'shared/numbers_only_javascript' %> | ... | ... |
app/views/manage_products/_edit_input.rhtml
1 | 1 | <% form_for(@input, :url => {:controller => 'manage_products', :action => 'edit_input', :id => @input}, |
2 | 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 | + | |
3 | 7 | <table> |
4 | 8 | <tr> |
5 | 9 | <td><%= f.label :amount_used, label_amount_used(@input), :class => 'formlabel' %></td> | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
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')) %></td> | |
5 | + <td> | |
6 | + <%= link_to_remote(_('Remove'), | |
7 | + :update => "price-detail-#{price_detail.id}", | |
8 | + :complete => "calculateValuesForBar();", | |
9 | + :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' %> | ... | ... |
... | ... | @@ -0,0 +1,43 @@ |
1 | +<div id='price-composition-bar'> | |
2 | + <%= render :partial => '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 => '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')) %></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' %> | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
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> | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
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/show.rhtml
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | |
24 | 24 | <br style='clear: both'/> |
25 | 25 | |
26 | - <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty?) %> | |
26 | + <% unless !@allowed_user && (@product.description.blank? && @product.inputs.empty? && !@product.price_described? ) %> | |
27 | 27 | <div class='ui-tabs' id='product-<%= @product.id %>-tabs'> |
28 | 28 | <ul> |
29 | 29 | <% if !@product.description.blank? || @allowed_user %> |
... | ... | @@ -32,6 +32,9 @@ |
32 | 32 | <% if !@product.inputs.empty? || @allowed_user %> |
33 | 33 | <li class='tab'><a href='#product-inputs'><%= _('Inputs and raw material') %></a></li> |
34 | 34 | <% end %> |
35 | + <% if @product.price_described? || @allowed_user %> | |
36 | + <li class='tab'><a href='#product-price-details'><%= _('Price composition') %></a></li> | |
37 | + <% end %> | |
35 | 38 | </ul> |
36 | 39 | <div id='product-description'> |
37 | 40 | <%= render :partial => 'manage_products/display_description' %> |
... | ... | @@ -39,6 +42,12 @@ |
39 | 42 | <div id='product-inputs'> |
40 | 43 | <%= render :partial => 'manage_products/display_inputs' %> |
41 | 44 | </div> |
45 | + <% if @product.price_described? || @allowed_user %> | |
46 | + <div id='product-price-details'> | |
47 | + <%= render :partial => 'manage_products/display_price_details' %> | |
48 | + <%= render :partial => 'manage_products/price_details_button' %> | |
49 | + </div> | |
50 | + <% end %> | |
42 | 51 | </div> |
43 | 52 | <% end %> |
44 | 53 | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<% product.product_qualifiers.each do |pq| %> | |
2 | + <% if pq.qualifier %> | |
3 | + <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span> | |
4 | + <% end %> | |
5 | + <% if pq.certifier %> | |
6 | + <span class="search-product-certifier"> <%= _('cert. ') + pq.certifier.name + _(";") %></span> | |
7 | + <% end %> | |
8 | + | |
9 | + <div style="clear: both"></div> | |
10 | +<% end %> | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +class CreateProductionCost < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :production_costs do |t| | |
4 | + t.string :name | |
5 | + t.references :owner, :polymorphic => true | |
6 | + t.timestamps | |
7 | + end | |
8 | + end | |
9 | + | |
10 | + def self.down | |
11 | + drop_table :production_costs | |
12 | + end | |
13 | +end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +class CreatePriceDetails < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :price_details do |t| | |
4 | + t.decimal :price, :default => 0 | |
5 | + t.references :product | |
6 | + t.references :production_cost | |
7 | + t.timestamps | |
8 | + end | |
9 | + end | |
10 | + | |
11 | + def self.down | |
12 | + drop_table :price_details | |
13 | + end | |
14 | +end | ... | ... |
db/schema.rb
... | ... | @@ -323,6 +323,14 @@ ActiveRecord::Schema.define(:version => 20111004184104) do |
323 | 323 | t.datetime "updated_at" |
324 | 324 | end |
325 | 325 | |
326 | + create_table "price_details", :force => true do |t| | |
327 | + t.decimal "price", :default => 0.0 | |
328 | + t.integer "product_id" | |
329 | + t.integer "production_cost_id" | |
330 | + t.datetime "created_at" | |
331 | + t.datetime "updated_at" | |
332 | + end | |
333 | + | |
326 | 334 | create_table "product_categorizations", :force => true do |t| |
327 | 335 | t.integer "category_id" |
328 | 336 | t.integer "product_id" |
... | ... | @@ -342,6 +350,14 @@ ActiveRecord::Schema.define(:version => 20111004184104) do |
342 | 350 | t.datetime "updated_at" |
343 | 351 | end |
344 | 352 | |
353 | + create_table "production_costs", :force => true do |t| | |
354 | + t.string "name" | |
355 | + t.integer "owner_id" | |
356 | + t.string "owner_type" | |
357 | + t.datetime "created_at" | |
358 | + t.datetime "updated_at" | |
359 | + end | |
360 | + | |
345 | 361 | create_table "products", :force => true do |t| |
346 | 362 | t.integer "enterprise_id" |
347 | 363 | t.integer "product_category_id" | ... | ... |
features/admin_categories.feature
... | ... | @@ -43,7 +43,7 @@ Feature: manage categories |
43 | 43 | When I follow "Show" |
44 | 44 | Then I should see "Vegetarian" |
45 | 45 | And I should see "Steak" |
46 | - When I follow "Hide" | |
46 | + When I follow "Hide" and sleep 1 second | |
47 | 47 | Then I should not see "Vegetarian" |
48 | 48 | And I should not see "Steak" |
49 | 49 | ... | ... |
... | ... | @@ -0,0 +1,309 @@ |
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 "disable_products_for_enterprises" is disabled 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 I should see "Associação de Artesanato de Bonito" | |
21 | + And I should see "Products/Services" within "#product-list" | |
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 | + And I should see "No image" within ".no-image" | |
71 | + And I should not see "product unavailable" | |
72 | + And I should not see "description" | |
73 | + And I should not see "qualifiers" | |
74 | + And I should not see "price composition" | |
75 | + | |
76 | + Scenario: product name links to product page | |
77 | + Given the following products | |
78 | + | owner | category | name | price | | |
79 | + | artebonito | categ1 | Produto1 | 50.00 | | |
80 | + And I am on /catalog/artebonito | |
81 | + When I follow "Produto1" within "li.product-link" | |
82 | + Then I should be taken to "Produto1" product page | |
83 | + | |
84 | + Scenario: display product with custom image | |
85 | + Given the following products | |
86 | + | owner | category | name | price | img | | |
87 | + | artebonito | categ1 | Agrotox | 12.34 | agrotox | | |
88 | + And I am on /catalog/artebonito | |
89 | + Then I should see "Agrotox" within "li.product-link" | |
90 | + And I should see "12.34" within "span.product-price" | |
91 | + And I should see "unit" within "span.product-unit" | |
92 | + And I should not see "No image" | |
93 | + And I should not see "product unavailable" | |
94 | + And I should not see "description" | |
95 | + And I should not see "qualifiers" | |
96 | + And I should not see "price composition" | |
97 | + | |
98 | + Scenario: display "zoom in" button | |
99 | + Given the following products | |
100 | + | owner | category | name | price | img | | |
101 | + | artebonito | categ1 | Agrotox | 12.34 | agrotox | | |
102 | + And I am on /catalog/artebonito | |
103 | + And I should not see "No image" | |
104 | + And I should see "Zoom in" within ".zoomify-image" | |
105 | + | |
106 | + Scenario: image links to product page | |
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 | + When I follow "Agrotox" within ".product-image-link" | |
112 | + Then I should be taken to "Agrotox" product page | |
113 | + | |
114 | + Scenario: display product with discount | |
115 | + Given the following products | |
116 | + | owner | category | name | price | discount | img | | |
117 | + | artebonito | categ1 | Semterrinha | 99.99 | 12.34 | semterrinha | | |
118 | + And I am on /catalog/artebonito | |
119 | + Then I should see "Semterrinha" within "li.product-link" | |
120 | + And I should see "99.99" within "span.product-discount" | |
121 | + And I should see "87.65" within "span.product-price" | |
122 | + And I should not see "No image" | |
123 | + And I should not see "description" | |
124 | + And I should not see "qualifiers" | |
125 | + And I should not see "price composition" | |
126 | + | |
127 | + @selenium | |
128 | + Scenario: display description button when needed (but not the description) | |
129 | + Given the following products | |
130 | + | owner | category | name | price | description | | |
131 | + | artebonito | categ1 | Produto2 | 12.34 | A small description for a product that doesn't exist. | | |
132 | + And I am on /catalog/artebonito | |
133 | + And I reload and wait for the page | |
134 | + Then I should see "Produto2" within "li.product-link" | |
135 | + And I should see "12.34" within "span.product-price" | |
136 | + And I should see "description" within "#product-description-button" | |
137 | + And the "product-description-button" should be visible | |
138 | + And I should see "A small description" within "#product-description" | |
139 | + And the "product-description" should not be visible | |
140 | + | |
141 | + @selenium | |
142 | + Scenario: display description when button is clicked | |
143 | + Given the following products | |
144 | + | owner | category | name | price | description | | |
145 | + | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. | | |
146 | + And I am on /catalog/artebonito | |
147 | + And I reload and wait for the page | |
148 | + When I click "product-description-button" | |
149 | + Then I should see "A small description" within "#product-description" | |
150 | + And the "product-description" should be visible | |
151 | + | |
152 | + @selenium | |
153 | + Scenario: hide description | |
154 | + Given the following products | |
155 | + | owner | category | name | price | description | | |
156 | + | artebonito | categ1 | Produto3 | 12.34 | A small description for a product that doesn't exist. | | |
157 | + And I am on /catalog/artebonito | |
158 | + And I reload and wait for the page | |
159 | + When I click "product-description-button" | |
160 | + Then I should see "A small description" within "#product-description" | |
161 | + And the "product-description" should be visible | |
162 | + When I click "product-list" | |
163 | + Then the "product-description" should not be visible | |
164 | + | |
165 | + Scenario: display unavailable product | |
166 | + Given the following products | |
167 | + | owner | category | name | price | available | | |
168 | + | artebonito | categ1 | Prod3 | 12.34 | false | | |
169 | + And I am on /catalog/artebonito | |
170 | + Then I should see "Prod3" within "li.not-available" | |
171 | + And I should see "12.34" within "li.not-available" | |
172 | + And I should see "product unavailable" within "li.product-unavailable" | |
173 | + And I should not see "qualifiers" | |
174 | + And I should not see "price composition" | |
175 | + | |
176 | + Scenario: display qualifiers | |
177 | + Given the following qualifiers | |
178 | + | name | | |
179 | + | Organic | | |
180 | + And the following certifiers | |
181 | + | name | qualifiers | | |
182 | + | Colivre | Organic | | |
183 | + And the following products | |
184 | + | owner | category | name | price | qualifier | | |
185 | + | artebonito | categ1 | Banana | 0.99 | Organic | | |
186 | + And I am on /catalog/artebonito | |
187 | + Then I should see "Banana" within "li.product-link" | |
188 | + And I should see "0.99" within "span.product-price" | |
189 | + And I should see "qualifiers" within "li.product-qualifiers" | |
190 | + And I should see "Organic" within "span.search-product-qualifier" | |
191 | + And I should not see "price composition" | |
192 | + | |
193 | + @selenium | |
194 | + Scenario: not display price composition button if price is not described | |
195 | + Given the following product | |
196 | + | owner | category | name | price | | |
197 | + | artebonito | food | Bananada | 10.00 | | |
198 | + And the following input | |
199 | + | product | category | price_per_unit | amount_used | | |
200 | + | Bananada | food | 0.99 | 5 | | |
201 | + And I am on /catalog/artebonito | |
202 | + And I reload and wait for the page | |
203 | + Then I should see "Bananada" within "li.product-link" | |
204 | + And I should see "10.00" within "span.product-price" | |
205 | + And the "#product-price-composition-button" should not be visible | |
206 | + | |
207 | + @selenium | |
208 | + Scenario: display price composition button (but not inputs) | |
209 | + Given the following product | |
210 | + | owner | category | name | price | | |
211 | + | artebonito | food | Bananada | 10.00 | | |
212 | + And the following input | |
213 | + | product | category | price_per_unit | amount_used | | |
214 | + | Bananada | food | 2.00 | 5 | | |
215 | + And I am on /catalog/artebonito | |
216 | + And I reload and wait for the page | |
217 | + Then I should see "Bananada" within "li.product-link" | |
218 | + And I should see "10.00" within "span.product-price" | |
219 | + And I should see "price composition" within "#product-price-composition-button" | |
220 | + And the "#product-price-composition-button" should be visible | |
221 | + And I should see "food" within "#product-price-composition" | |
222 | + And I should see "10.00" within "#product-price-composition" | |
223 | + | |
224 | + @selenium | |
225 | + Scenario: display price composition when button is clicked | |
226 | + Given the following product | |
227 | + | owner | category | name | price | | |
228 | + | artebonito | food | Bananada | 10.88 | | |
229 | + And the following input | |
230 | + | product | category | price_per_unit | amount_used | | |
231 | + | Bananada | food | 2.72 | 4 | | |
232 | + And I am on /catalog/artebonito | |
233 | + And I reload and wait for the page | |
234 | + When I click "#product-price-composition-button" | |
235 | + Then the "#product-price-composition" should be visible | |
236 | + And I should see "food" within "#product-price-composition" | |
237 | + And I should see "10.88" within "#product-price-composition" | |
238 | + | |
239 | + @selenium | |
240 | + Scenario: display inputs and raw materials button when not completely filled | |
241 | + Given the following product | |
242 | + | owner | category | name | price | | |
243 | + | artebonito | food | Vitamina | 17.99 | | |
244 | + And the following unit | |
245 | + | name | plural | | |
246 | + | Liter | Liters | | |
247 | + And the following input | |
248 | + | product | category | | |
249 | + | Vitamina | food | | |
250 | + And I am on /catalog/artebonito | |
251 | + And I reload and wait for the page | |
252 | + Then the "#inputs-button" should be visible | |
253 | + And I should see "inputs and raw materials" within "#inputs-button" | |
254 | + | |
255 | + @selenium | |
256 | + Scenario: display inputs and raw materials button | |
257 | + Given the following product | |
258 | + | owner | category | name | price | | |
259 | + | artebonito | food | Vitamina | 17.99 | | |
260 | + And the following unit | |
261 | + | name | plural | | |
262 | + | Liter | Liters | | |
263 | + And the following input | |
264 | + | product | category | price_per_unit | amount_used | unit | | |
265 | + | Vitamina | food | 1.45 | 7 | Liter | | |
266 | + And I am on /catalog/artebonito | |
267 | + And I reload and wait for the page | |
268 | + Then I should see "Vitamina" within "li.product-link" | |
269 | + And I should see "17.99" within "span.product-price" | |
270 | + And the "#inputs-button" should be visible | |
271 | + And I should see "inputs and raw materials" within "#inputs-button" | |
272 | + And the "#inputs-description" should not be visible | |
273 | + And I should see "7.0 Liter of food" within "#inputs-description" | |
274 | + | |
275 | + @selenium | |
276 | + Scenario: display inputs and raw materials description | |
277 | + Given the following product | |
278 | + | owner | category | name | price | | |
279 | + | artebonito | food | Vitamina | 17.99 | | |
280 | + And the following unit | |
281 | + | name | plural | | |
282 | + | Liter | Liters | | |
283 | + And the following input | |
284 | + | product | category | price_per_unit | amount_used | unit | | |
285 | + | Vitamina | food | 1.45 | 7 | Liter | | |
286 | + And I am on /catalog/artebonito | |
287 | + And I reload and wait for the page | |
288 | + When I click "#inputs-button" | |
289 | + Then the "#inputs-description" should be visible | |
290 | + And I should see "7.0 Liter of food" within "#inputs-description" | |
291 | + | |
292 | + @selenium | |
293 | + Scenario: hide inputs and raw materials | |
294 | + Given the following product | |
295 | + | owner | category | name | price | | |
296 | + | artebonito | food | Vitamina | 17.99 | | |
297 | + And the following unit | |
298 | + | name | plural | | |
299 | + | Liter | Liters | | |
300 | + And the following input | |
301 | + | product | category | price_per_unit | amount_used | unit | | |
302 | + | Vitamina | food | 1.45 | 7 | Liter | | |
303 | + And I am on /catalog/artebonito | |
304 | + And I reload and wait for the page | |
305 | + When I click "#inputs-button" | |
306 | + Then the "#inputs-description" should be visible | |
307 | + And I should see "7.0 Liter of food" within "#inputs-description" | |
308 | + When I click "#product-list" | |
309 | + Then the "#inputs-description" should not be visible | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +Feature: browse enterprises | |
2 | + As a noosfero user | |
3 | + I want to browse enterprises | |
4 | + | |
5 | +Background: | |
6 | + Given the following enterprises | |
7 | + | identifier | name | | |
8 | + | shop1 | Shoes Shop | | |
9 | + And feature "disable_products_for_enterprises" is disabled on environment | |
10 | + And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment | |
11 | + | |
12 | +Scenario: show all enterprises | |
13 | + Given the following enterprises | |
14 | + | identifier | name | | |
15 | + | shop2 | Fruits Shop | | |
16 | + Given I am on /assets/enterprises | |
17 | + Then I should see "Enterprises" | |
18 | + And I should see "Shoes Shop" | |
19 | + And I should see "Fruits Shop" | |
20 | + | |
21 | +Scenario: show profile links button | |
22 | + Given I am on /assets/enterprises | |
23 | + Then I should see "Profile links" within "a.enterprise-trigger" | |
24 | + And I should not see "Members" | |
25 | + And I should not see "Agenda" | |
26 | + | |
27 | +@selenium | |
28 | +Scenario: show profile links when clicked | |
29 | + Given I am on /assets/enterprises | |
30 | + When I follow "Profile links" | |
31 | + Then I should see "Products" within "ul.menu-submenu-list" | |
32 | + And I should see "Members" within "ul.menu-submenu-list" | |
33 | + And I should see "Agenda" within "ul.menu-submenu-list" | |
34 | + | |
35 | +@selenium | |
36 | +Scenario: go to catalog when click on products link | |
37 | + Given I am on /assets/enterprises | |
38 | + When I follow "Profile links" | |
39 | + And I follow "Products" and wait | |
40 | + Then I should be exactly on /catalog/shop1 | ... | ... |
... | ... | @@ -0,0 +1,38 @@ |
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 | + | |
25 | + | |
26 | + Scenario: display profile info | |
27 | + When I go to /mayhem/homepage | |
28 | + Then I should see "queen@workerbees.org" | |
29 | + And I should see "(288) 555-0153" | |
30 | + | |
31 | + Scenario: display products list | |
32 | + When I go to /mayhem/homepage | |
33 | + Then I should see "Natural Handmade" | |
34 | + | |
35 | + Scenario: display link to product | |
36 | + When I go to /mayhem/homepage | |
37 | + And I follow "Natural Handmade" | |
38 | + Then I should be taken to "Natural Handmade" product page | ... | ... |
... | ... | @@ -0,0 +1,178 @@ |
1 | +Feature: manage product price details | |
2 | + As an enterprise owner | |
3 | + I want to manage the details of product's price | |
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 | + | redemoinho | joaosilva | Rede Moinho | true | | |
12 | + Given the following product_category | |
13 | + | name | | |
14 | + | Music | | |
15 | + And the following product_categories | |
16 | + | name | parent | | |
17 | + | Rock | music | | |
18 | + | CD Player | music | | |
19 | + And the following product | |
20 | + | owner | category | name | price | | |
21 | + | redemoinho | rock | Abbey Road | 80.0 | | |
22 | + And feature "disable_products_for_enterprises" is disabled on environment | |
23 | + And the following inputs | |
24 | + | product | category | price_per_unit | amount_used | | |
25 | + | Abbey Road | Rock | 10.0 | 2 | | |
26 | + | Abbey Road | CD Player | 20.0 | 2 | | |
27 | + And the following production cost | |
28 | + | name | owner | | |
29 | + | Taxes | environment | | |
30 | + And I am logged in as "joaosilva" | |
31 | + | |
32 | + @selenium | |
33 | + Scenario: list total value of inputs as price details | |
34 | + Given I go to Rede Moinho's page of product Abbey Road | |
35 | + And I follow "Price composition" | |
36 | + And I follow "Describe here the cost of production" | |
37 | + Then I should see "Inputs" | |
38 | + And I should see "60.0" within ".inputs-cost" | |
39 | + | |
40 | + @selenium | |
41 | + Scenario: return to product after save | |
42 | + Given I go to Rede Moinho's page of product Abbey Road | |
43 | + And I follow "Price composition" | |
44 | + And I follow "Describe here the cost of production" | |
45 | + And I press "Save" | |
46 | + Then I should be on Rede Moinho's page of product Abbey Road | |
47 | + | |
48 | + @selenium | |
49 | + Scenario: add first item on price details | |
50 | + Given I go to Rede Moinho's page of product Abbey Road | |
51 | + And I follow "Price composition" | |
52 | + And I follow "Describe here the cost of production" | |
53 | + And I follow "New cost" | |
54 | + And I select "Taxes" | |
55 | + And I fill in "$" with "5.00" | |
56 | + And I leave the ".price-details-price" field | |
57 | + And I press "Save" | |
58 | + Then I should not see "Save" | |
59 | + And I should see "Describe here the cost of production" | |
60 | + | |
61 | + @selenium | |
62 | + Scenario: edit a production cost | |
63 | + Given the following production cost | |
64 | + | name | owner | | |
65 | + | Energy | environment | | |
66 | + When I go to Rede Moinho's page of product Abbey Road | |
67 | + And I follow "Price composition" | |
68 | + And I follow "Describe here the cost of production" | |
69 | + And I follow "New cost" | |
70 | + And I select "Taxes" | |
71 | + And I fill in "$" with "20.00" | |
72 | + And I leave the ".price-details-price" field | |
73 | + And I press "Save" | |
74 | + Then I should not see "Save" | |
75 | + And I should see "Taxes" within "#display-price-details" | |
76 | + When I follow "Describe here the cost of production" | |
77 | + And I select "Energy" | |
78 | + And I leave the ".price-details-price" field | |
79 | + And I press "Save" | |
80 | + And I should not see "Taxes" within "#display-price-details" | |
81 | + And I should see "Energy" within "#display-price-details" | |
82 | + | |
83 | + Scenario: not display product detail button if product does not have input | |
84 | + Given the following product | |
85 | + | owner | category | name | | |
86 | + | redemoinho | rock | Yellow Submarine | | |
87 | + And the following user | |
88 | + | login | name | | |
89 | + | mariasouza | Maria Souza | | |
90 | + And I am logged in as "mariasouza" | |
91 | + When I go to Rede Moinho's page of product Yellow Submarine | |
92 | + And I follow "Price composition" | |
93 | + Then I should not see "Describe here the cost of production" | |
94 | + | |
95 | + Scenario: not display price details if price is not fully described | |
96 | + Given I am not logged in | |
97 | + And I go to Rede Moinho's page of product Abbey Road | |
98 | + Then I should not see "60.0" | |
99 | + | |
100 | + @selenium | |
101 | + Scenario: display price details if price is fully described | |
102 | + Given I go to Rede Moinho's page of product Abbey Road | |
103 | + And I follow "Price composition" | |
104 | + And I follow "Describe here the cost of production" | |
105 | + And I follow "New cost" | |
106 | + And I select "Taxes" | |
107 | + And I fill in "$" with "20.00" | |
108 | + And I press "Save" | |
109 | + Then I should see "Inputs" within ".price-detail-name" | |
110 | + And I should see "60.0" within ".price-detail-price" | |
111 | + | |
112 | + @selenium | |
113 | + Scenario: create a new cost clicking on select | |
114 | + Given I go to Rede Moinho's page of product Abbey Road | |
115 | + And I follow "Price composition" | |
116 | + And I follow "Describe here the cost of production" | |
117 | + And I follow "New cost" | |
118 | + And I want to add "Energy" as cost | |
119 | + And I select "Other cost" | |
120 | + And I fill in "$" with "10.00" | |
121 | + And I leave the ".price-details-price" field | |
122 | + And I press "Save" | |
123 | + When I follow "Describe here the cost of production" | |
124 | + Then I should see "Energy" within ".production-cost-selection" | |
125 | + | |
126 | + @selenium | |
127 | + Scenario: add created cost on new-cost-fields | |
128 | + Given I go to Rede Moinho's page of product Abbey Road | |
129 | + And I follow "Price composition" | |
130 | + And I follow "Describe here the cost of production" | |
131 | + And I want to add "Energy" as cost | |
132 | + And I select "Other cost" | |
133 | + Then I should see "Energy" within "#new-cost-fields" | |
134 | + | |
135 | + @selenium | |
136 | + Scenario: remove price detail | |
137 | + Given the following price detail | |
138 | + | product | production_cost | price | | |
139 | + | Abbey Road | Taxes | 20.0 | | |
140 | + And I go to Rede Moinho's page of product Abbey Road | |
141 | + And I follow "Price composition" | |
142 | + And I follow "Describe here the cost of production" | |
143 | + And I should see "Taxes" within "#manage-product-details-form" | |
144 | + When I follow "Remove" within "#manage-product-details-form" | |
145 | + And I confirm | |
146 | + And I press "Save" | |
147 | + And I follow "Describe here the cost of production" | |
148 | + Then I should not see "Taxes" within "#manage-product-details-form" | |
149 | + | |
150 | + Scenario: display progressbar | |
151 | + Given I go to Rede Moinho's page of product Abbey Road | |
152 | + And I follow "Price composition" | |
153 | + And I follow "Describe here the cost of production" | |
154 | + Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | |
155 | + | |
156 | + @selenium | |
157 | + Scenario: update value on progressbar after addition of new cost | |
158 | + Given I go to Rede Moinho's page of product Abbey Road | |
159 | + And I follow "Price composition" | |
160 | + And I follow "Describe here the cost of production" | |
161 | + Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | |
162 | + And I follow "New cost" | |
163 | + And I fill in "$" with "10.00" | |
164 | + And I leave the ".price-details-price" field | |
165 | + Then I should see "$ 70.00 of $ 80.00" within "#progressbar-text" | |
166 | + | |
167 | + @selenium | |
168 | + Scenario: update value on progressbar after editing an input | |
169 | + Given I go to Rede Moinho's page of product Abbey Road | |
170 | + And I follow "Price composition" | |
171 | + And I follow "Describe here the cost of production" | |
172 | + Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | |
173 | + When I follow "Inputs" | |
174 | + And I follow "Edit" within ".input-details" | |
175 | + And I fill in "Price" with "23.31" | |
176 | + And I press "Save" | |
177 | + Then I follow "Price composition" | |
178 | + And I should see "$ 86.62 of $ 80.00" within "#progressbar-text" | ... | ... |
features/manage_products.feature
... | ... | @@ -35,19 +35,20 @@ Feature: manage products |
35 | 35 | | redemoinho | bicycle | Bike J | bicycle 10 | |
36 | 36 | | redemoinho | bicycle | Bike K | bicycle 11 | |
37 | 37 | When I go to /catalog/redemoinho |
38 | - Then I should see "Bike A" within "#product_list" | |
39 | - And I should see "Bike B" within "#product_list" | |
40 | - And I should see "Bike C" within "#product_list" | |
41 | - And I should see "Bike D" within "#product_list" | |
42 | - And I should see "Bike E" within "#product_list" | |
43 | - And I should see "Bike F" within "#product_list" | |
44 | - And I should see "Bike G" within "#product_list" | |
45 | - And I should see "Bike H" within "#product_list" | |
46 | - And I should see "Bike I" within "#product_list" | |
47 | - And I should see "Bike J" within "#product_list" | |
48 | - And I should not see "Bike K" within "#product_list" | |
38 | + Then I should see "Bike A" within "#product-list" | |
39 | + And I should see "Bike B" within "#product-list" | |
40 | + And I should see "Bike C" within "#product-list" | |
41 | + And I should see "Bike D" within "#product-list" | |
42 | + And I should see "Bike E" within "#product-list" | |
43 | + And I should see "Bike F" within "#product-list" | |
44 | + And I should see "Bike G" within "#product-list" | |
45 | + And I should see "Bike H" within "#product-list" | |
46 | + And I should see "Bike I" within "#product-list" | |
47 | + And I should not see "Bike J" within "#product-list" | |
48 | + And I should not see "Bike K" within "#product-list" | |
49 | 49 | When I follow "Next" |
50 | - Then I should see "Bike K" within "#product_list" | |
50 | + Then I should see "Bike J" within "#product-list" | |
51 | + Then I should see "Bike K" within "#product-list" | |
51 | 52 | |
52 | 53 | Scenario: listing products and services |
53 | 54 | Given I am logged in as "joaosilva" | ... | ... |
features/profile_domain.feature
features/step_definitions/noosfero_steps.rb
... | ... | @@ -150,8 +150,16 @@ Given /^the following products?$/ do |table| |
150 | 150 | data = item.dup |
151 | 151 | owner = Enterprise[data.delete("owner")] |
152 | 152 | category = Category.find_by_slug(data.delete("category").to_slug) |
153 | - img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
154 | - product = Product.create!(data.merge(:enterprise => owner, :product_category => category, :image_id => img.id)) | |
153 | + data.merge!(:enterprise => owner, :product_category => category) | |
154 | + if data[:img] | |
155 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/'+data.delete("img")+'.png', 'image/png')) | |
156 | + data.merge!(:image_id => img.id) | |
157 | + end | |
158 | + if data[:qualifier] | |
159 | + qualifier = Qualifier.find_by_name(data.delete("qualifier")) | |
160 | + data.merge!(:qualifiers => [qualifier]) | |
161 | + end | |
162 | + product = Product.create!(data) | |
155 | 163 | end |
156 | 164 | end |
157 | 165 | |
... | ... | @@ -214,6 +222,22 @@ Given /^the following certifiers$/ do |table| |
214 | 222 | end |
215 | 223 | end |
216 | 224 | |
225 | +Given /^the following production costs?$/ do |table| | |
226 | + table.hashes.map{|item| item.dup}.each do |item| | |
227 | + owner_type = item.delete('owner') | |
228 | + owner = owner_type == 'environment' ? Environment.default : Profile[owner_type] | |
229 | + ProductionCost.create!(item.merge(:owner => owner)) | |
230 | + end | |
231 | +end | |
232 | + | |
233 | +Given /^the following price details?$/ do |table| | |
234 | + table.hashes.map{|item| item.dup}.each do |item| | |
235 | + product = Product.find_by_name item.delete('product') | |
236 | + production_cost = ProductionCost.find_by_name item.delete('production_cost') | |
237 | + product.price_details.create!(item.merge(:production_cost => production_cost)) | |
238 | + end | |
239 | +end | |
240 | + | |
217 | 241 | Given /^I am logged in as "(.+)"$/ do |username| |
218 | 242 | visit('/account/logout') |
219 | 243 | visit('/account/login') |
... | ... | @@ -493,3 +517,32 @@ end |
493 | 517 | When 'I log off' do |
494 | 518 | visit '/account/logout' |
495 | 519 | end |
520 | + | |
521 | +Then /^I should be taken to "([^\"]*)" product page$/ do |product_name| | |
522 | + product = Product.find_by_name(product_name) | |
523 | + path = url_for(product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product, :only_path => true)) | |
524 | + if response.class.to_s == 'Webrat::SeleniumResponse' | |
525 | + URI.parse(response.selenium.get_location).path.should == path_to(path) | |
526 | + else | |
527 | + URI.parse(current_url).path.should == path_to(path) | |
528 | + end | |
529 | +end | |
530 | + | |
531 | +When /^I reload and wait for the page$/ do | |
532 | + response.selenium.refresh | |
533 | + selenium.wait_for_page | |
534 | +end | |
535 | + | |
536 | +Given /^the following enterprise homepages?$/ do |table| | |
537 | + # table is a Cucumber::Ast::Table | |
538 | + table.hashes.each do |item| | |
539 | + data = item.dup | |
540 | + home = EnterpriseHomepage.new(:name => data[:name]) | |
541 | + ent = Enterprise.find_by_identifier(data[:enterprise]) | |
542 | + ent.articles << home | |
543 | + end | |
544 | +end | |
545 | + | |
546 | +And /^I want to add "([^\"]*)" as cost$/ do |string| | |
547 | + selenium.answer_on_next_prompt(string) | |
548 | +end | ... | ... |
features/step_definitions/selenium_steps.rb
... | ... | @@ -117,3 +117,17 @@ Then /^the select for category "([^\"]*)" should be visible$/ do |name| |
117 | 117 | category = Category.find_by_name(name) |
118 | 118 | selenium.is_visible(string_to_element_locator("option=#{category.id}")).should be_true |
119 | 119 | end |
120 | + | |
121 | +When /^I follow "([^\"]*)" and sleep ([^\"]*) seconds?$/ do |link, time| | |
122 | + click_link(link) | |
123 | + sleep time.to_i | |
124 | +end | |
125 | + | |
126 | +When /^I follow "([^\"]*)" and wait for jquery$/ do |link| | |
127 | + click_link(link) | |
128 | + selenium.wait_for(:wait_for => :ajax, :javascript_framework => framework) | |
129 | +end | |
130 | + | |
131 | +When /^I leave the "([^\"]+)" field$/ do |field| | |
132 | + selenium.fire_event("css=#{field}", "blur") | |
133 | +end | ... | ... |
features/step_definitions/webrat_steps.rb
plugins/shopping_cart/controllers/shopping_cart_plugin_profile_controller.rb
... | ... | @@ -118,7 +118,7 @@ class ShoppingCartPluginProfileController < ProfileController |
118 | 118 | session[:cart][:visibility] = true |
119 | 119 | render :text => { |
120 | 120 | :ok => true, |
121 | - :message => _('Cart displayed.'), | |
121 | + :message => _('Basket displayed.'), | |
122 | 122 | :error => {:code => 0} |
123 | 123 | }.to_json |
124 | 124 | rescue Exception => exception |
... | ... | @@ -137,7 +137,7 @@ class ShoppingCartPluginProfileController < ProfileController |
137 | 137 | session[:cart][:visibility] = false |
138 | 138 | render :text => { |
139 | 139 | :ok => true, |
140 | - :message => _('Cart Hidden.'), | |
140 | + :message => _('Basket hidden.'), | |
141 | 141 | :error => {:code => 0} |
142 | 142 | }.to_json |
143 | 143 | rescue Exception => exception |
... | ... | @@ -173,7 +173,7 @@ class ShoppingCartPluginProfileController < ProfileController |
173 | 173 | :ok => false, |
174 | 174 | :error => { |
175 | 175 | :code => 2, |
176 | - :message => _("There is no cart.") | |
176 | + :message => _("There is no basket.") | |
177 | 177 | } |
178 | 178 | }.to_json |
179 | 179 | return false |
... | ... | @@ -203,7 +203,7 @@ class ShoppingCartPluginProfileController < ProfileController |
203 | 203 | :ok => false, |
204 | 204 | :error => { |
205 | 205 | :code => 4, |
206 | - :message => _("The cart doesn't have this product.") | |
206 | + :message => _("The basket doesn't have this product.") | |
207 | 207 | } |
208 | 208 | }.to_json |
209 | 209 | return false | ... | ... |
plugins/shopping_cart/lib/shopping_cart_plugin.rb
... | ... | @@ -4,17 +4,17 @@ require_dependency 'shopping_cart_plugin/ext/person' |
4 | 4 | class ShoppingCartPlugin < Noosfero::Plugin |
5 | 5 | |
6 | 6 | def self.plugin_name |
7 | - "Shopping Cart" | |
7 | + "Shopping Basket" | |
8 | 8 | end |
9 | 9 | |
10 | 10 | def self.plugin_description |
11 | - _("A shopping cart feature for enterprises") | |
11 | + _("A shopping basket feature for enterprises") | |
12 | 12 | end |
13 | 13 | |
14 | 14 | def add_to_cart_button(item, enterprise = context.profile) |
15 | 15 | if enterprise.shopping_cart && item.available |
16 | 16 | lambda { |
17 | - link_to(_('Add to cart'), "add:#{item.name}", | |
17 | + link_to(_('Add to basket'), "add:#{item.name}", | |
18 | 18 | :class => 'cart-add-item', |
19 | 19 | :onclick => "Cart.addItem('#{enterprise.identifier}', #{item.id}, this); return false" |
20 | 20 | ) |
... | ... | @@ -41,10 +41,10 @@ class ShoppingCartPlugin < Noosfero::Plugin |
41 | 41 | def control_panel_buttons |
42 | 42 | buttons = [] |
43 | 43 | if context.profile.enterprise? |
44 | - buttons << { :title => 'Shopping cart', :icon => 'shopping_cart_icon', :url => {:controller => 'shopping_cart_plugin_myprofile', :action => 'edit'} } | |
44 | + buttons << { :title => _('Shopping basket'), :icon => 'shopping-cart-icon', :url => {:controller => 'shopping_cart_plugin_myprofile', :action => 'edit'} } | |
45 | 45 | end |
46 | 46 | if context.profile.enterprise? && context.profile.shopping_cart |
47 | - buttons << { :title => 'Purchase reports', :icon => 'shopping-cart-purchase-report', :url => {:controller => 'shopping_cart_plugin_myprofile', :action => 'reports'} } | |
47 | + buttons << { :title => _('Purchase reports'), :icon => 'shopping-cart-purchase-report', :url => {:controller => 'shopping_cart_plugin_myprofile', :action => 'reports'} } | |
48 | 48 | end |
49 | 49 | |
50 | 50 | buttons | ... | ... |
plugins/shopping_cart/public/cart.js
... | ... | @@ -62,7 +62,7 @@ function Cart(config) { |
62 | 62 | '<div class="item-price">' + |
63 | 63 | '<input size="1" value="'+item.quantity+'" />'+ (item.price ? '× '+ item.price : '') +'</div>' + |
64 | 64 | ' <a href="remove:'+item.name+'" onclick="Cart.removeItem(\''+this.enterprise+'\', '+item.id+'); return false"' + |
65 | - ' class="button icon-delete"><span>remove</span></a>' | |
65 | + ' class="button icon-remove"><span>remove</span></a>' | |
66 | 66 | ).appendTo(li); |
67 | 67 | var input = $("input", li)[0]; |
68 | 68 | input.lastValue = input.value; |
... | ... | @@ -304,6 +304,10 @@ function Cart(config) { |
304 | 304 | }); |
305 | 305 | } |
306 | 306 | |
307 | + Cart.colorbox_close = function() { | |
308 | + $.colorbox.close(); | |
309 | + } | |
310 | + | |
307 | 311 | $(function(){ |
308 | 312 | $('.cart-add-item').button({ icons: { primary: 'ui-icon-cart'} }) |
309 | 313 | }); | ... | ... |
827 Bytes
351 Bytes
1.96 KB
plugins/shopping_cart/public/images/control-panel/icon.svg
0 → 100644
... | ... | @@ -0,0 +1,120 @@ |
1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
2 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> | |
3 | + | |
4 | +<svg | |
5 | + xmlns:dc="http://purl.org/dc/elements/1.1/" | |
6 | + xmlns:cc="http://creativecommons.org/ns#" | |
7 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |
8 | + xmlns:svg="http://www.w3.org/2000/svg" | |
9 | + xmlns="http://www.w3.org/2000/svg" | |
10 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
11 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
12 | + width="744.09448819" | |
13 | + height="1052.3622047" | |
14 | + id="svg3362" | |
15 | + version="1.1" | |
16 | + inkscape:version="0.48.2 r9819" | |
17 | + sodipodi:docname="icone.svg"> | |
18 | + <defs | |
19 | + id="defs3364" /> | |
20 | + <sodipodi:namedview | |
21 | + id="base" | |
22 | + pagecolor="#ffffff" | |
23 | + bordercolor="#666666" | |
24 | + borderopacity="1.0" | |
25 | + inkscape:pageopacity="0.0" | |
26 | + inkscape:pageshadow="2" | |
27 | + inkscape:zoom="0.7" | |
28 | + inkscape:cx="278.97361" | |
29 | + inkscape:cy="689.0069" | |
30 | + inkscape:document-units="px" | |
31 | + inkscape:current-layer="layer1" | |
32 | + showgrid="false" | |
33 | + inkscape:window-width="1366" | |
34 | + inkscape:window-height="721" | |
35 | + inkscape:window-x="-3" | |
36 | + inkscape:window-y="-3" | |
37 | + inkscape:window-maximized="1" /> | |
38 | + <metadata | |
39 | + id="metadata3367"> | |
40 | + <rdf:RDF> | |
41 | + <cc:Work | |
42 | + rdf:about=""> | |
43 | + <dc:format>image/svg+xml</dc:format> | |
44 | + <dc:type | |
45 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |
46 | + <dc:title></dc:title> | |
47 | + </cc:Work> | |
48 | + </rdf:RDF> | |
49 | + </metadata> | |
50 | + <g | |
51 | + inkscape:label="Layer 1" | |
52 | + inkscape:groupmode="layer" | |
53 | + id="layer1"> | |
54 | + <g | |
55 | + id="g5575-7" | |
56 | + transform="matrix(0.07006136,0,0,0.07006136,-271.48534,-209.48041)" | |
57 | + style="fill:#d38d5f"> | |
58 | + <path | |
59 | + inkscape:connector-curvature="0" | |
60 | + id="rect5245-9-6" | |
61 | + d="m 6408.0436,5064.9271 c -11.726,-11.2912 -32.3679,-9.6218 -42.4594,3.1418 -19.6123,19.9856 -39.9641,39.4417 -59.1428,59.74 -9.518,12.5005 -6.3676,31.3823 5.826,40.9329 19.6892,19.3981 38.735,39.51 58.8119,58.4787 12.3484,9.5947 31.3846,6.505 40.8262,-5.7528 19.4803,-19.979 39.9713,-39.2016 58.856,-59.6292 9.0558,-12.4283 5.7503,-30.9531 -6.2232,-40.3134 -18.839,-18.8581 -37.6197,-37.7778 -56.4947,-56.598 z" | |
62 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
63 | + <path | |
64 | + inkscape:connector-curvature="0" | |
65 | + id="rect5245-3-6-2" | |
66 | + d="m 6271.4191,5203.1033 c -11.659,-11.815 -32.7156,-10.3098 -42.9669,2.6329 -19.7244,20.2091 -40.4303,39.6819 -59.5621,60.3374 -9.0337,12.4807 -5.8043,30.8944 6.2011,40.2912 19.927,19.5313 39.0995,40.0758 59.474,59.0098 12.4653,9.0761 30.8739,5.764 40.2082,-6.2396 19.3801,-19.7478 39.4876,-38.9701 58.4368,-59.0318 9.4652,-12.3353 6.4045,-31.4347 -5.8482,-40.9551 -18.655,-18.6738 -37.2518,-37.4088 -55.9429,-56.0448 z" | |
67 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
68 | + <path | |
69 | + inkscape:connector-curvature="0" | |
70 | + id="rect5245-8-6-2" | |
71 | + d="m 6545.5287,5202.6829 c -11.7363,-11.3217 -32.3801,-9.5656 -42.4593,3.1418 -19.5937,19.9946 -39.9139,39.3349 -59.0767,59.7178 -9.5513,12.3449 -6.4556,31.438 5.7819,40.9772 19.6941,19.3922 38.7293,39.519 58.8119,58.4788 12.4118,9.6084 31.3584,6.4621 40.8704,-5.797 19.3229,-19.7402 39.4821,-38.8781 58.3264,-58.9655 9.5617,-12.3467 6.4938,-31.475 -5.7378,-40.933 -18.8464,-18.8655 -37.6344,-37.7925 -56.5168,-56.6201 z" | |
72 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
73 | + <path | |
74 | + inkscape:connector-curvature="0" | |
75 | + id="rect5245-7-4-7" | |
76 | + d="m 6683.1903,5065.7678 c -11.6727,-11.8214 -32.6711,-10.2704 -42.9667,2.6331 -19.5831,19.9842 -39.9685,39.3886 -59.0767,59.7177 -9.5608,12.3477 -6.4907,31.4696 5.7376,40.9329 19.6964,19.4311 38.8692,39.5905 58.8782,58.5894 12.4019,9.5309 31.358,6.4013 40.8042,-5.8192 19.3581,-19.7586 39.4434,-38.8626 58.3704,-59.0098 9.5628,-12.3863 6.44,-31.439 -5.7818,-40.977 -18.6625,-18.6812 -37.2665,-37.4235 -55.9652,-56.0671 z" | |
77 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
78 | + <path | |
79 | + inkscape:connector-curvature="0" | |
80 | + id="rect5245-5-2-8" | |
81 | + d="m 6820.3665,5203.4794 c -11.6211,-11.8358 -32.7205,-10.3463 -42.9888,2.6109 -19.6161,19.9836 -39.9579,39.4428 -59.1429,59.7399 -9.5091,12.4948 -6.4432,31.3232 5.7819,40.8887 19.7364,19.4377 38.8215,39.6072 58.9443,58.6115 12.2819,9.5014 31.2571,6.4201 40.7379,-5.8413 19.38,-19.7479 39.4876,-38.9702 58.4367,-59.0319 9.212,-12.1115 6.6473,-30.6982 -5.1419,-40.247 -18.8831,-18.9025 -37.708,-37.8662 -56.6272,-56.7308 z" | |
82 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
83 | + <path | |
84 | + inkscape:connector-curvature="0" | |
85 | + id="rect5245-5-4-1-9" | |
86 | + d="m 6662,5332.625 c -15.2378,0.1612 -24.0529,14.157 -34.1146,23.4276 -15.476,15.9413 -31.8697,31.086 -46.7916,47.5099 -2.9405,4.2478 -4.8192,9.3664 -5.1563,14.4687 58.2812,-0.042 116.7292,0.083 174.9063,-0.062 -0.7632,-15.4178 -15.3649,-24.1142 -24.7148,-34.6559 -15.4837,-15.0104 -30.156,-31.1956 -46.0978,-45.5317 -5.23,-3.6558 -11.6538,-5.4746 -18.0312,-5.1562 z" | |
87 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
88 | + <path | |
89 | + inkscape:connector-curvature="0" | |
90 | + id="rect5245-5-4-4-4-1" | |
91 | + d="m 6387.75,5331.1875 c -12.8167,-0.2843 -21.9125,9.8823 -29.9201,18.4726 -16.9981,17.3803 -34.8059,34.2122 -51.3299,51.9024 -3.1649,4.3908 -5.2116,9.685 -5.5625,15.0313 58.2812,-0.042 116.7292,0.083 174.9063,-0.063 -0.723,-15.0722 -14.844,-23.7682 -24.0397,-33.9792 -15.7089,-15.2187 -30.5296,-31.6073 -46.7416,-46.1458 -5.0231,-3.5423 -11.1737,-5.3579 -17.3125,-5.2187 z" | |
92 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
93 | + <path | |
94 | + inkscape:connector-curvature="0" | |
95 | + id="rect5245-5-4-7-7-7" | |
96 | + d="m 6438.0625,5011.4375 c 0.8844,15.3847 15.3961,24.0874 24.746,34.5934 15.4791,14.996 30.0891,31.1552 46.0665,45.4691 12.3222,9.0732 30.8351,5.8023 40.1691,-6.1752 19.3539,-19.7366 39.5157,-38.9385 58.3934,-58.981 3.1742,-4.3805 5.1726,-9.6672 5.5625,-15.0313 -58.2707,0.083 -116.8752,-0.1665 -174.9375,0.125 z" | |
97 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
98 | + <path | |
99 | + inkscape:connector-curvature="0" | |
100 | + id="rect5245-5-4-7-4-6-5" | |
101 | + d="m 6701.375,5008.75 c 27.4204,26.9864 54.2733,54.7791 81.9688,81.3438 12.312,9.5662 31.425,6.3692 40.8246,-5.801 59.1737,-59.3365 118.4716,-118.5488 177.7691,-177.7616 -100.1875,34.073 -200.375,68.1459 -300.5625,102.2188 z" | |
102 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
103 | + <path | |
104 | + inkscape:connector-curvature="0" | |
105 | + id="rect5245-5-4-7-4-3-3-0" | |
106 | + d="m 6998.8438,4984.5938 c -47.3943,47.7404 -95.4006,94.9567 -142.5626,142.875 -10.1297,12.3088 -7.0115,31.8296 5.3324,41.3869 25.2451,25.1714 50.3907,50.4424 75.5426,75.7068 34.073,-100.1875 68.1459,-200.375 102.2188,-300.5625 -13.5104,13.5313 -27.0208,27.0625 -40.5312,40.5938 z" | |
107 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
108 | + <path | |
109 | + inkscape:connector-curvature="0" | |
110 | + id="rect5245-5-4-7-4-2-3-8" | |
111 | + d="m 6114.2812,5244.9062 c 26.8771,-27.2005 54.2641,-54.0149 80.875,-81.4062 10.0644,-12.3049 7.0844,-31.7597 -5.3634,-41.3871 -59.3365,-59.1737 -118.5488,-118.4717 -177.7616,-177.7691 34.0834,100.1874 68.1667,200.375 102.25,300.5624 z" | |
112 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
113 | + <path | |
114 | + inkscape:connector-curvature="0" | |
115 | + id="rect5245-5-4-7-4-3-5-8-2" | |
116 | + d="m 6090.125,4947.4375 c 47.677,47.4093 94.9671,95.3478 142.7812,142.5313 12.3096,10.0651 31.7648,7.1628 41.4222,-5.2972 25.2023,-25.2247 50.4579,-50.3961 75.7341,-75.5466 -100.1875,-34.0729 -200.375,-68.1458 -300.5625,-102.2188 13.5417,13.5105 27.0833,27.0209 40.625,40.5313 z" | |
117 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
118 | + </g> | |
119 | + </g> | |
120 | +</svg> | ... | ... |
1.6 KB
plugins/shopping_cart/public/images/control-panel/purchase-report.png
plugins/shopping_cart/public/images/control-panel/purchase-report.svg
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | height="48" |
15 | 15 | id="svg2" |
16 | 16 | version="1.1" |
17 | - inkscape:version="0.47 r22583" | |
17 | + inkscape:version="0.48.2 r9819" | |
18 | 18 | sodipodi:docname="purchase-report.svg" |
19 | 19 | inkscape:export-filename="/home/aurium/purchase-report.png" |
20 | 20 | inkscape:export-xdpi="90" |
... | ... | @@ -352,10 +352,10 @@ |
352 | 352 | inkscape:document-units="px" |
353 | 353 | inkscape:current-layer="layer1" |
354 | 354 | showgrid="true" |
355 | - inkscape:window-width="1440" | |
356 | - inkscape:window-height="827" | |
357 | - inkscape:window-x="0" | |
358 | - inkscape:window-y="25" | |
355 | + inkscape:window-width="1366" | |
356 | + inkscape:window-height="721" | |
357 | + inkscape:window-x="-3" | |
358 | + inkscape:window-y="-3" | |
359 | 359 | inkscape:window-maximized="1"> |
360 | 360 | <inkscape:grid |
361 | 361 | type="xygrid" |
... | ... | @@ -419,120 +419,17 @@ |
419 | 419 | ry="0" /> |
420 | 420 | <g |
421 | 421 | id="g4873" |
422 | - mask="url(#mask4922)"> | |
423 | - <g | |
424 | - transform="translate(6,1)" | |
425 | - id="g4757"> | |
426 | - <path | |
427 | - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" | |
428 | - d="m 2.5,2.5 2,0 0,8 12,0 0,-6" | |
429 | - id="path2839" | |
430 | - transform="translate(0,1004.3622)" | |
431 | - sodipodi:nodetypes="ccccc" /> | |
432 | - <path | |
433 | - sodipodi:nodetypes="cccccc" | |
434 | - id="path3619" | |
435 | - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0" | |
436 | - d="m 15,1012.8622 -9.5,0 m 9.5,-2 -9.5,0 m 9.5,-2 -9.5,0" /> | |
437 | - <path | |
438 | - transform="translate(7.5,1000.8622)" | |
439 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
440 | - sodipodi:ry="1.5" | |
441 | - sodipodi:rx="1.5" | |
442 | - sodipodi:cy="16" | |
443 | - sodipodi:cx="7" | |
444 | - id="path3647" | |
445 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
446 | - sodipodi:type="arc" /> | |
447 | - <path | |
448 | - sodipodi:type="arc" | |
449 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
450 | - id="path4776" | |
451 | - sodipodi:cx="7" | |
452 | - sodipodi:cy="16" | |
453 | - sodipodi:rx="1.5" | |
454 | - sodipodi:ry="1.5" | |
455 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
456 | - transform="translate(-1,1000.8622)" /> | |
457 | - </g> | |
458 | - <g | |
459 | - id="g4778" | |
460 | - transform="translate(6,15)"> | |
461 | - <path | |
462 | - sodipodi:nodetypes="ccccc" | |
463 | - transform="translate(0,1004.3622)" | |
464 | - id="path4780" | |
465 | - d="m 2.5,2.5 2,0 0,8 12,0 0,-6" | |
466 | - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /> | |
467 | - <path | |
468 | - d="m 15,1012.8622 -9.5,0 m 9.5,-2 -9.5,0 m 9.5,-2 -9.5,0" | |
469 | - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0" | |
470 | - id="path4782" | |
471 | - sodipodi:nodetypes="cccccc" /> | |
472 | - <path | |
473 | - sodipodi:type="arc" | |
474 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
475 | - id="path4784" | |
476 | - sodipodi:cx="7" | |
477 | - sodipodi:cy="16" | |
478 | - sodipodi:rx="1.5" | |
479 | - sodipodi:ry="1.5" | |
480 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
481 | - transform="translate(7.5,1000.8622)" /> | |
482 | - <path | |
483 | - transform="translate(-1,1000.8622)" | |
484 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
485 | - sodipodi:ry="1.5" | |
486 | - sodipodi:rx="1.5" | |
487 | - sodipodi:cy="16" | |
488 | - sodipodi:cx="7" | |
489 | - id="path4786" | |
490 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
491 | - sodipodi:type="arc" /> | |
492 | - </g> | |
493 | - <g | |
494 | - transform="translate(6,29)" | |
495 | - id="g4788"> | |
496 | - <path | |
497 | - style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" | |
498 | - d="m 2.5,2.5 2,0 0,8 12,0 0,-6" | |
499 | - id="path4790" | |
500 | - transform="translate(0,1004.3622)" | |
501 | - sodipodi:nodetypes="ccccc" /> | |
502 | - <path | |
503 | - sodipodi:nodetypes="cccccc" | |
504 | - id="path4792" | |
505 | - style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0" | |
506 | - d="m 15,1012.8622 -9.5,0 m 9.5,-2 -9.5,0 m 9.5,-2 -9.5,0" /> | |
507 | - <path | |
508 | - transform="translate(7.5,1000.8622)" | |
509 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
510 | - sodipodi:ry="1.5" | |
511 | - sodipodi:rx="1.5" | |
512 | - sodipodi:cy="16" | |
513 | - sodipodi:cx="7" | |
514 | - id="path4794" | |
515 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
516 | - sodipodi:type="arc" /> | |
517 | - <path | |
518 | - sodipodi:type="arc" | |
519 | - style="color:#000000;fill:#000000;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" | |
520 | - id="path4796" | |
521 | - sodipodi:cx="7" | |
522 | - sodipodi:cy="16" | |
523 | - sodipodi:rx="1.5" | |
524 | - sodipodi:ry="1.5" | |
525 | - d="m 8.5,16 c 0,0.828427 -0.6715729,1.5 -1.5,1.5 -0.8284271,0 -1.5,-0.671573 -1.5,-1.5 0,-0.828427 0.6715729,-1.5 1.5,-1.5 0.8284271,0 1.5,0.671573 1.5,1.5 z" | |
526 | - transform="translate(-1,1000.8622)" /> | |
527 | - </g> | |
422 | + mask="url(#mask4922)" | |
423 | + transform="translate(0,1.7382813e-5)"> | |
528 | 424 | <path |
529 | 425 | sodipodi:nodetypes="cccccc" |
530 | 426 | d="m 29.5,1015.8622 11,0 m -11,-3 11,0 m -11,-3 11,0" |
531 | 427 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" |
532 | - id="path4802" /> | |
428 | + id="path4802" | |
429 | + inkscape:connector-curvature="0" /> | |
533 | 430 | <path |
534 | 431 | transform="translate(0,1004.3622)" |
535 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
432 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
536 | 433 | sodipodi:ry="1" |
537 | 434 | sodipodi:rx="1" |
538 | 435 | sodipodi:cy="5.5" |
... | ... | @@ -548,11 +445,11 @@ |
548 | 445 | sodipodi:cy="5.5" |
549 | 446 | sodipodi:rx="1" |
550 | 447 | sodipodi:ry="1" |
551 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
448 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
552 | 449 | transform="translate(0,1007.3622)" /> |
553 | 450 | <path |
554 | 451 | transform="translate(0,1010.3622)" |
555 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
452 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
556 | 453 | sodipodi:ry="1" |
557 | 454 | sodipodi:rx="1" |
558 | 455 | sodipodi:cy="5.5" |
... | ... | @@ -564,7 +461,8 @@ |
564 | 461 | id="path4811" |
565 | 462 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" |
566 | 463 | d="m 29.5,1029.8622 11,0 m -11,-3 11,0 m -11,-3 11,0" |
567 | - sodipodi:nodetypes="cccccc" /> | |
464 | + sodipodi:nodetypes="cccccc" | |
465 | + inkscape:connector-curvature="0" /> | |
568 | 466 | <path |
569 | 467 | sodipodi:type="arc" |
570 | 468 | style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
... | ... | @@ -573,11 +471,11 @@ |
573 | 471 | sodipodi:cy="5.5" |
574 | 472 | sodipodi:rx="1" |
575 | 473 | sodipodi:ry="1" |
576 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
474 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
577 | 475 | transform="translate(0,1018.3622)" /> |
578 | 476 | <path |
579 | 477 | transform="translate(0,1021.3622)" |
580 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
478 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
581 | 479 | sodipodi:ry="1" |
582 | 480 | sodipodi:rx="1" |
583 | 481 | sodipodi:cy="5.5" |
... | ... | @@ -593,15 +491,16 @@ |
593 | 491 | sodipodi:cy="5.5" |
594 | 492 | sodipodi:rx="1" |
595 | 493 | sodipodi:ry="1" |
596 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
494 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
597 | 495 | transform="translate(0,1024.3622)" /> |
598 | 496 | <path |
599 | 497 | id="path4827" |
600 | 498 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" |
601 | - d="m 29.5,1038.8622 11,0 m -11,3 11,0 m -11,3 9,0" /> | |
499 | + d="m 29.5,1038.8622 11,0 m -11,3 11,0 m -11,3 9,0" | |
500 | + inkscape:connector-curvature="0" /> | |
602 | 501 | <path |
603 | 502 | transform="translate(0,1033.3622)" |
604 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
503 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
605 | 504 | sodipodi:ry="1" |
606 | 505 | sodipodi:rx="1" |
607 | 506 | sodipodi:cy="5.5" |
... | ... | @@ -617,11 +516,11 @@ |
617 | 516 | sodipodi:cy="5.5" |
618 | 517 | sodipodi:rx="1" |
619 | 518 | sodipodi:ry="1" |
620 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
519 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
621 | 520 | transform="translate(0,1036.3622)" /> |
622 | 521 | <path |
623 | 522 | transform="translate(0,1039.3622)" |
624 | - d="m 27.5,5.5 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" | |
523 | + d="m 27.5,5.5 c 0,0.5522847 -0.447715,1 -1,1 -0.552285,0 -1,-0.4477153 -1,-1 0,-0.5522847 0.447715,-1 1,-1 0.552285,0 1,0.4477153 1,1 z" | |
625 | 524 | sodipodi:ry="1" |
626 | 525 | sodipodi:rx="1" |
627 | 526 | sodipodi:cy="5.5" |
... | ... | @@ -629,6 +528,201 @@ |
629 | 528 | id="path4833" |
630 | 529 | style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
631 | 530 | sodipodi:type="arc" /> |
531 | + <g | |
532 | + id="g5575-7" | |
533 | + transform="matrix(0.01545762,0,0,0.01545762,-84.564216,932.96399)" | |
534 | + style="fill:#d38d5f"> | |
535 | + <path | |
536 | + inkscape:connector-curvature="0" | |
537 | + id="rect5245-9-6" | |
538 | + d="m 6408.0436,5064.9271 c -11.726,-11.2912 -32.3679,-9.6218 -42.4594,3.1418 -19.6123,19.9856 -39.9641,39.4417 -59.1428,59.74 -9.518,12.5005 -6.3676,31.3823 5.826,40.9329 19.6892,19.3981 38.735,39.51 58.8119,58.4787 12.3484,9.5947 31.3846,6.505 40.8262,-5.7528 19.4803,-19.979 39.9713,-39.2016 58.856,-59.6292 9.0558,-12.4283 5.7503,-30.9531 -6.2232,-40.3134 -18.839,-18.8581 -37.6197,-37.7778 -56.4947,-56.598 z" | |
539 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
540 | + <path | |
541 | + inkscape:connector-curvature="0" | |
542 | + id="rect5245-3-6-2" | |
543 | + d="m 6271.4191,5203.1033 c -11.659,-11.815 -32.7156,-10.3098 -42.9669,2.6329 -19.7244,20.2091 -40.4303,39.6819 -59.5621,60.3374 -9.0337,12.4807 -5.8043,30.8944 6.2011,40.2912 19.927,19.5313 39.0995,40.0758 59.474,59.0098 12.4653,9.0761 30.8739,5.764 40.2082,-6.2396 19.3801,-19.7478 39.4876,-38.9701 58.4368,-59.0318 9.4652,-12.3353 6.4045,-31.4347 -5.8482,-40.9551 -18.655,-18.6738 -37.2518,-37.4088 -55.9429,-56.0448 z" | |
544 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
545 | + <path | |
546 | + inkscape:connector-curvature="0" | |
547 | + id="rect5245-8-6-2" | |
548 | + d="m 6545.5287,5202.6829 c -11.7363,-11.3217 -32.3801,-9.5656 -42.4593,3.1418 -19.5937,19.9946 -39.9139,39.3349 -59.0767,59.7178 -9.5513,12.3449 -6.4556,31.438 5.7819,40.9772 19.6941,19.3922 38.7293,39.519 58.8119,58.4788 12.4118,9.6084 31.3584,6.4621 40.8704,-5.797 19.3229,-19.7402 39.4821,-38.8781 58.3264,-58.9655 9.5617,-12.3467 6.4938,-31.475 -5.7378,-40.933 -18.8464,-18.8655 -37.6344,-37.7925 -56.5168,-56.6201 z" | |
549 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
550 | + <path | |
551 | + inkscape:connector-curvature="0" | |
552 | + id="rect5245-7-4-7" | |
553 | + d="m 6683.1903,5065.7678 c -11.6727,-11.8214 -32.6711,-10.2704 -42.9667,2.6331 -19.5831,19.9842 -39.9685,39.3886 -59.0767,59.7177 -9.5608,12.3477 -6.4907,31.4696 5.7376,40.9329 19.6964,19.4311 38.8692,39.5905 58.8782,58.5894 12.4019,9.5309 31.358,6.4013 40.8042,-5.8192 19.3581,-19.7586 39.4434,-38.8626 58.3704,-59.0098 9.5628,-12.3863 6.44,-31.439 -5.7818,-40.977 -18.6625,-18.6812 -37.2665,-37.4235 -55.9652,-56.0671 z" | |
554 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
555 | + <path | |
556 | + inkscape:connector-curvature="0" | |
557 | + id="rect5245-5-2-8" | |
558 | + d="m 6820.3665,5203.4794 c -11.6211,-11.8358 -32.7205,-10.3463 -42.9888,2.6109 -19.6161,19.9836 -39.9579,39.4428 -59.1429,59.7399 -9.5091,12.4948 -6.4432,31.3232 5.7819,40.8887 19.7364,19.4377 38.8215,39.6072 58.9443,58.6115 12.2819,9.5014 31.2571,6.4201 40.7379,-5.8413 19.38,-19.7479 39.4876,-38.9702 58.4367,-59.0319 9.212,-12.1115 6.6473,-30.6982 -5.1419,-40.247 -18.8831,-18.9025 -37.708,-37.8662 -56.6272,-56.7308 z" | |
559 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
560 | + <path | |
561 | + inkscape:connector-curvature="0" | |
562 | + id="rect5245-5-4-1-9" | |
563 | + d="m 6662,5332.625 c -15.2378,0.1612 -24.0529,14.157 -34.1146,23.4276 -15.476,15.9413 -31.8697,31.086 -46.7916,47.5099 -2.9405,4.2478 -4.8192,9.3664 -5.1563,14.4687 58.2812,-0.042 116.7292,0.083 174.9063,-0.062 -0.7632,-15.4178 -15.3649,-24.1142 -24.7148,-34.6559 -15.4837,-15.0104 -30.156,-31.1956 -46.0978,-45.5317 -5.23,-3.6558 -11.6538,-5.4746 -18.0312,-5.1562 z" | |
564 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
565 | + <path | |
566 | + inkscape:connector-curvature="0" | |
567 | + id="rect5245-5-4-4-4-1" | |
568 | + d="m 6387.75,5331.1875 c -12.8167,-0.2843 -21.9125,9.8823 -29.9201,18.4726 -16.9981,17.3803 -34.8059,34.2122 -51.3299,51.9024 -3.1649,4.3908 -5.2116,9.685 -5.5625,15.0313 58.2812,-0.042 116.7292,0.083 174.9063,-0.063 -0.723,-15.0722 -14.844,-23.7682 -24.0397,-33.9792 -15.7089,-15.2187 -30.5296,-31.6073 -46.7416,-46.1458 -5.0231,-3.5423 -11.1737,-5.3579 -17.3125,-5.2187 z" | |
569 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
570 | + <path | |
571 | + inkscape:connector-curvature="0" | |
572 | + id="rect5245-5-4-7-7-7" | |
573 | + d="m 6438.0625,5011.4375 c 0.8844,15.3847 15.3961,24.0874 24.746,34.5934 15.4791,14.996 30.0891,31.1552 46.0665,45.4691 12.3222,9.0732 30.8351,5.8023 40.1691,-6.1752 19.3539,-19.7366 39.5157,-38.9385 58.3934,-58.981 3.1742,-4.3805 5.1726,-9.6672 5.5625,-15.0313 -58.2707,0.083 -116.8752,-0.1665 -174.9375,0.125 z" | |
574 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
575 | + <path | |
576 | + inkscape:connector-curvature="0" | |
577 | + id="rect5245-5-4-7-4-6-5" | |
578 | + d="m 6701.375,5008.75 c 27.4204,26.9864 54.2733,54.7791 81.9688,81.3438 12.312,9.5662 31.425,6.3692 40.8246,-5.801 59.1737,-59.3365 118.4716,-118.5488 177.7691,-177.7616 -100.1875,34.073 -200.375,68.1459 -300.5625,102.2188 z" | |
579 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
580 | + <path | |
581 | + inkscape:connector-curvature="0" | |
582 | + id="rect5245-5-4-7-4-3-3-0" | |
583 | + d="m 6998.8438,4984.5938 c -47.3943,47.7404 -95.4006,94.9567 -142.5626,142.875 -10.1297,12.3088 -7.0115,31.8296 5.3324,41.3869 25.2451,25.1714 50.3907,50.4424 75.5426,75.7068 34.073,-100.1875 68.1459,-200.375 102.2188,-300.5625 -13.5104,13.5313 -27.0208,27.0625 -40.5312,40.5938 z" | |
584 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
585 | + <path | |
586 | + inkscape:connector-curvature="0" | |
587 | + id="rect5245-5-4-7-4-2-3-8" | |
588 | + d="m 6114.2812,5244.9062 c 26.8771,-27.2005 54.2641,-54.0149 80.875,-81.4062 10.0644,-12.3049 7.0844,-31.7597 -5.3634,-41.3871 -59.3365,-59.1737 -118.5488,-118.4717 -177.7616,-177.7691 34.0834,100.1874 68.1667,200.375 102.25,300.5624 z" | |
589 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
590 | + <path | |
591 | + inkscape:connector-curvature="0" | |
592 | + id="rect5245-5-4-7-4-3-5-8-2" | |
593 | + d="m 6090.125,4947.4375 c 47.677,47.4093 94.9671,95.3478 142.7812,142.5313 12.3096,10.0651 31.7648,7.1628 41.4222,-5.2972 25.2023,-25.2247 50.4579,-50.3961 75.7341,-75.5466 -100.1875,-34.0729 -200.375,-68.1458 -300.5625,-102.2188 13.5417,13.5105 27.0833,27.0209 40.625,40.5313 z" | |
594 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
595 | + </g> | |
596 | + <g | |
597 | + id="g5575-7-8" | |
598 | + transform="matrix(0.01545762,0,0,0.01545762,-84.486184,947.26528)" | |
599 | + style="fill:#d38d5f"> | |
600 | + <path | |
601 | + inkscape:connector-curvature="0" | |
602 | + id="rect5245-9-6-5" | |
603 | + d="m 6408.0436,5064.9271 c -11.726,-11.2912 -32.3679,-9.6218 -42.4594,3.1418 -19.6123,19.9856 -39.9641,39.4417 -59.1428,59.74 -9.518,12.5005 -6.3676,31.3823 5.826,40.9329 19.6892,19.3981 38.735,39.51 58.8119,58.4787 12.3484,9.5947 31.3846,6.505 40.8262,-5.7528 19.4803,-19.979 39.9713,-39.2016 58.856,-59.6292 9.0558,-12.4283 5.7503,-30.9531 -6.2232,-40.3134 -18.839,-18.8581 -37.6197,-37.7778 -56.4947,-56.598 z" | |
604 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
605 | + <path | |
606 | + inkscape:connector-curvature="0" | |
607 | + id="rect5245-3-6-2-0" | |
608 | + d="m 6271.4191,5203.1033 c -11.659,-11.815 -32.7156,-10.3098 -42.9669,2.6329 -19.7244,20.2091 -40.4303,39.6819 -59.5621,60.3374 -9.0337,12.4807 -5.8043,30.8944 6.2011,40.2912 19.927,19.5313 39.0995,40.0758 59.474,59.0098 12.4653,9.0761 30.8739,5.764 40.2082,-6.2396 19.3801,-19.7478 39.4876,-38.9701 58.4368,-59.0318 9.4652,-12.3353 6.4045,-31.4347 -5.8482,-40.9551 -18.655,-18.6738 -37.2518,-37.4088 -55.9429,-56.0448 z" | |
609 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
610 | + <path | |
611 | + inkscape:connector-curvature="0" | |
612 | + id="rect5245-8-6-2-9" | |
613 | + d="m 6545.5287,5202.6829 c -11.7363,-11.3217 -32.3801,-9.5656 -42.4593,3.1418 -19.5937,19.9946 -39.9139,39.3349 -59.0767,59.7178 -9.5513,12.3449 -6.4556,31.438 5.7819,40.9772 19.6941,19.3922 38.7293,39.519 58.8119,58.4788 12.4118,9.6084 31.3584,6.4621 40.8704,-5.797 19.3229,-19.7402 39.4821,-38.8781 58.3264,-58.9655 9.5617,-12.3467 6.4938,-31.475 -5.7378,-40.933 -18.8464,-18.8655 -37.6344,-37.7925 -56.5168,-56.6201 z" | |
614 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
615 | + <path | |
616 | + inkscape:connector-curvature="0" | |
617 | + id="rect5245-7-4-7-6" | |
618 | + d="m 6683.1903,5065.7678 c -11.6727,-11.8214 -32.6711,-10.2704 -42.9667,2.6331 -19.5831,19.9842 -39.9685,39.3886 -59.0767,59.7177 -9.5608,12.3477 -6.4907,31.4696 5.7376,40.9329 19.6964,19.4311 38.8692,39.5905 58.8782,58.5894 12.4019,9.5309 31.358,6.4013 40.8042,-5.8192 19.3581,-19.7586 39.4434,-38.8626 58.3704,-59.0098 9.5628,-12.3863 6.44,-31.439 -5.7818,-40.977 -18.6625,-18.6812 -37.2665,-37.4235 -55.9652,-56.0671 z" | |
619 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
620 | + <path | |
621 | + inkscape:connector-curvature="0" | |
622 | + id="rect5245-5-2-8-3" | |
623 | + d="m 6820.3665,5203.4794 c -11.6211,-11.8358 -32.7205,-10.3463 -42.9888,2.6109 -19.6161,19.9836 -39.9579,39.4428 -59.1429,59.7399 -9.5091,12.4948 -6.4432,31.3232 5.7819,40.8887 19.7364,19.4377 38.8215,39.6072 58.9443,58.6115 12.2819,9.5014 31.2571,6.4201 40.7379,-5.8413 19.38,-19.7479 39.4876,-38.9702 58.4367,-59.0319 9.212,-12.1115 6.6473,-30.6982 -5.1419,-40.247 -18.8831,-18.9025 -37.708,-37.8662 -56.6272,-56.7308 z" | |
624 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
625 | + <path | |
626 | + inkscape:connector-curvature="0" | |
627 | + id="rect5245-5-4-1-9-8" | |
628 | + d="m 6662,5332.625 c -15.2378,0.1612 -24.0529,14.157 -34.1146,23.4276 -15.476,15.9413 -31.8697,31.086 -46.7916,47.5099 -2.9405,4.2478 -4.8192,9.3664 -5.1563,14.4687 58.2812,-0.042 116.7292,0.083 174.9063,-0.062 -0.7632,-15.4178 -15.3649,-24.1142 -24.7148,-34.6559 -15.4837,-15.0104 -30.156,-31.1956 -46.0978,-45.5317 -5.23,-3.6558 -11.6538,-5.4746 -18.0312,-5.1562 z" | |
629 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
630 | + <path | |
631 | + inkscape:connector-curvature="0" | |
632 | + id="rect5245-5-4-4-4-1-5" | |
633 | + d="m 6387.75,5331.1875 c -12.8167,-0.2843 -21.9125,9.8823 -29.9201,18.4726 -16.9981,17.3803 -34.8059,34.2122 -51.3299,51.9024 -3.1649,4.3908 -5.2116,9.685 -5.5625,15.0313 58.2812,-0.042 116.7292,0.083 174.9063,-0.063 -0.723,-15.0722 -14.844,-23.7682 -24.0397,-33.9792 -15.7089,-15.2187 -30.5296,-31.6073 -46.7416,-46.1458 -5.0231,-3.5423 -11.1737,-5.3579 -17.3125,-5.2187 z" | |
634 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
635 | + <path | |
636 | + inkscape:connector-curvature="0" | |
637 | + id="rect5245-5-4-7-7-7-6" | |
638 | + d="m 6438.0625,5011.4375 c 0.8844,15.3847 15.3961,24.0874 24.746,34.5934 15.4791,14.996 30.0891,31.1552 46.0665,45.4691 12.3222,9.0732 30.8351,5.8023 40.1691,-6.1752 19.3539,-19.7366 39.5157,-38.9385 58.3934,-58.981 3.1742,-4.3805 5.1726,-9.6672 5.5625,-15.0313 -58.2707,0.083 -116.8752,-0.1665 -174.9375,0.125 z" | |
639 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
640 | + <path | |
641 | + inkscape:connector-curvature="0" | |
642 | + id="rect5245-5-4-7-4-6-5-1" | |
643 | + d="m 6701.375,5008.75 c 27.4204,26.9864 54.2733,54.7791 81.9688,81.3438 12.312,9.5662 31.425,6.3692 40.8246,-5.801 59.1737,-59.3365 118.4716,-118.5488 177.7691,-177.7616 -100.1875,34.073 -200.375,68.1459 -300.5625,102.2188 z" | |
644 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
645 | + <path | |
646 | + inkscape:connector-curvature="0" | |
647 | + id="rect5245-5-4-7-4-3-3-0-1" | |
648 | + d="m 6998.8438,4984.5938 c -47.3943,47.7404 -95.4006,94.9567 -142.5626,142.875 -10.1297,12.3088 -7.0115,31.8296 5.3324,41.3869 25.2451,25.1714 50.3907,50.4424 75.5426,75.7068 34.073,-100.1875 68.1459,-200.375 102.2188,-300.5625 -13.5104,13.5313 -27.0208,27.0625 -40.5312,40.5938 z" | |
649 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
650 | + <path | |
651 | + inkscape:connector-curvature="0" | |
652 | + id="rect5245-5-4-7-4-2-3-8-5" | |
653 | + d="m 6114.2812,5244.9062 c 26.8771,-27.2005 54.2641,-54.0149 80.875,-81.4062 10.0644,-12.3049 7.0844,-31.7597 -5.3634,-41.3871 -59.3365,-59.1737 -118.5488,-118.4717 -177.7616,-177.7691 34.0834,100.1874 68.1667,200.375 102.25,300.5624 z" | |
654 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
655 | + <path | |
656 | + inkscape:connector-curvature="0" | |
657 | + id="rect5245-5-4-7-4-3-5-8-2-9" | |
658 | + d="m 6090.125,4947.4375 c 47.677,47.4093 94.9671,95.3478 142.7812,142.5313 12.3096,10.0651 31.7648,7.1628 41.4222,-5.2972 25.2023,-25.2247 50.4579,-50.3961 75.7341,-75.5466 -100.1875,-34.0729 -200.375,-68.1458 -300.5625,-102.2188 13.5417,13.5105 27.0833,27.0209 40.625,40.5313 z" | |
659 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
660 | + </g> | |
661 | + <g | |
662 | + id="g5575-7-8-8" | |
663 | + transform="matrix(0.01545762,0,0,0.01545762,-84.564216,961.96398)" | |
664 | + style="fill:#d38d5f"> | |
665 | + <path | |
666 | + inkscape:connector-curvature="0" | |
667 | + id="rect5245-9-6-5-4" | |
668 | + d="m 6408.0436,5064.9271 c -11.726,-11.2912 -32.3679,-9.6218 -42.4594,3.1418 -19.6123,19.9856 -39.9641,39.4417 -59.1428,59.74 -9.518,12.5005 -6.3676,31.3823 5.826,40.9329 19.6892,19.3981 38.735,39.51 58.8119,58.4787 12.3484,9.5947 31.3846,6.505 40.8262,-5.7528 19.4803,-19.979 39.9713,-39.2016 58.856,-59.6292 9.0558,-12.4283 5.7503,-30.9531 -6.2232,-40.3134 -18.839,-18.8581 -37.6197,-37.7778 -56.4947,-56.598 z" | |
669 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
670 | + <path | |
671 | + inkscape:connector-curvature="0" | |
672 | + id="rect5245-3-6-2-0-8" | |
673 | + d="m 6271.4191,5203.1033 c -11.659,-11.815 -32.7156,-10.3098 -42.9669,2.6329 -19.7244,20.2091 -40.4303,39.6819 -59.5621,60.3374 -9.0337,12.4807 -5.8043,30.8944 6.2011,40.2912 19.927,19.5313 39.0995,40.0758 59.474,59.0098 12.4653,9.0761 30.8739,5.764 40.2082,-6.2396 19.3801,-19.7478 39.4876,-38.9701 58.4368,-59.0318 9.4652,-12.3353 6.4045,-31.4347 -5.8482,-40.9551 -18.655,-18.6738 -37.2518,-37.4088 -55.9429,-56.0448 z" | |
674 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
675 | + <path | |
676 | + inkscape:connector-curvature="0" | |
677 | + id="rect5245-8-6-2-9-1" | |
678 | + d="m 6545.5287,5202.6829 c -11.7363,-11.3217 -32.3801,-9.5656 -42.4593,3.1418 -19.5937,19.9946 -39.9139,39.3349 -59.0767,59.7178 -9.5513,12.3449 -6.4556,31.438 5.7819,40.9772 19.6941,19.3922 38.7293,39.519 58.8119,58.4788 12.4118,9.6084 31.3584,6.4621 40.8704,-5.797 19.3229,-19.7402 39.4821,-38.8781 58.3264,-58.9655 9.5617,-12.3467 6.4938,-31.475 -5.7378,-40.933 -18.8464,-18.8655 -37.6344,-37.7925 -56.5168,-56.6201 z" | |
679 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
680 | + <path | |
681 | + inkscape:connector-curvature="0" | |
682 | + id="rect5245-7-4-7-6-0" | |
683 | + d="m 6683.1903,5065.7678 c -11.6727,-11.8214 -32.6711,-10.2704 -42.9667,2.6331 -19.5831,19.9842 -39.9685,39.3886 -59.0767,59.7177 -9.5608,12.3477 -6.4907,31.4696 5.7376,40.9329 19.6964,19.4311 38.8692,39.5905 58.8782,58.5894 12.4019,9.5309 31.358,6.4013 40.8042,-5.8192 19.3581,-19.7586 39.4434,-38.8626 58.3704,-59.0098 9.5628,-12.3863 6.44,-31.439 -5.7818,-40.977 -18.6625,-18.6812 -37.2665,-37.4235 -55.9652,-56.0671 z" | |
684 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
685 | + <path | |
686 | + inkscape:connector-curvature="0" | |
687 | + id="rect5245-5-2-8-3-3" | |
688 | + d="m 6820.3665,5203.4794 c -11.6211,-11.8358 -32.7205,-10.3463 -42.9888,2.6109 -19.6161,19.9836 -39.9579,39.4428 -59.1429,59.7399 -9.5091,12.4948 -6.4432,31.3232 5.7819,40.8887 19.7364,19.4377 38.8215,39.6072 58.9443,58.6115 12.2819,9.5014 31.2571,6.4201 40.7379,-5.8413 19.38,-19.7479 39.4876,-38.9702 58.4367,-59.0319 9.212,-12.1115 6.6473,-30.6982 -5.1419,-40.247 -18.8831,-18.9025 -37.708,-37.8662 -56.6272,-56.7308 z" | |
689 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
690 | + <path | |
691 | + inkscape:connector-curvature="0" | |
692 | + id="rect5245-5-4-1-9-8-0" | |
693 | + d="m 6662,5332.625 c -15.2378,0.1612 -24.0529,14.157 -34.1146,23.4276 -15.476,15.9413 -31.8697,31.086 -46.7916,47.5099 -2.9405,4.2478 -4.8192,9.3664 -5.1563,14.4687 58.2812,-0.042 116.7292,0.083 174.9063,-0.062 -0.7632,-15.4178 -15.3649,-24.1142 -24.7148,-34.6559 -15.4837,-15.0104 -30.156,-31.1956 -46.0978,-45.5317 -5.23,-3.6558 -11.6538,-5.4746 -18.0312,-5.1562 z" | |
694 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
695 | + <path | |
696 | + inkscape:connector-curvature="0" | |
697 | + id="rect5245-5-4-4-4-1-5-4" | |
698 | + d="m 6387.75,5331.1875 c -12.8167,-0.2843 -21.9125,9.8823 -29.9201,18.4726 -16.9981,17.3803 -34.8059,34.2122 -51.3299,51.9024 -3.1649,4.3908 -5.2116,9.685 -5.5625,15.0313 58.2812,-0.042 116.7292,0.083 174.9063,-0.063 -0.723,-15.0722 -14.844,-23.7682 -24.0397,-33.9792 -15.7089,-15.2187 -30.5296,-31.6073 -46.7416,-46.1458 -5.0231,-3.5423 -11.1737,-5.3579 -17.3125,-5.2187 z" | |
699 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
700 | + <path | |
701 | + inkscape:connector-curvature="0" | |
702 | + id="rect5245-5-4-7-7-7-6-4" | |
703 | + d="m 6438.0625,5011.4375 c 0.8844,15.3847 15.3961,24.0874 24.746,34.5934 15.4791,14.996 30.0891,31.1552 46.0665,45.4691 12.3222,9.0732 30.8351,5.8023 40.1691,-6.1752 19.3539,-19.7366 39.5157,-38.9385 58.3934,-58.981 3.1742,-4.3805 5.1726,-9.6672 5.5625,-15.0313 -58.2707,0.083 -116.8752,-0.1665 -174.9375,0.125 z" | |
704 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
705 | + <path | |
706 | + inkscape:connector-curvature="0" | |
707 | + id="rect5245-5-4-7-4-6-5-1-4" | |
708 | + d="m 6701.375,5008.75 c 27.4204,26.9864 54.2733,54.7791 81.9688,81.3438 12.312,9.5662 31.425,6.3692 40.8246,-5.801 59.1737,-59.3365 118.4716,-118.5488 177.7691,-177.7616 -100.1875,34.073 -200.375,68.1459 -300.5625,102.2188 z" | |
709 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
710 | + <path | |
711 | + inkscape:connector-curvature="0" | |
712 | + id="rect5245-5-4-7-4-3-3-0-1-4" | |
713 | + d="m 6998.8438,4984.5938 c -47.3943,47.7404 -95.4006,94.9567 -142.5626,142.875 -10.1297,12.3088 -7.0115,31.8296 5.3324,41.3869 25.2451,25.1714 50.3907,50.4424 75.5426,75.7068 34.073,-100.1875 68.1459,-200.375 102.2188,-300.5625 -13.5104,13.5313 -27.0208,27.0625 -40.5312,40.5938 z" | |
714 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
715 | + <path | |
716 | + inkscape:connector-curvature="0" | |
717 | + id="rect5245-5-4-7-4-2-3-8-5-7" | |
718 | + d="m 6114.2812,5244.9062 c 26.8771,-27.2005 54.2641,-54.0149 80.875,-81.4062 10.0644,-12.3049 7.0844,-31.7597 -5.3634,-41.3871 -59.3365,-59.1737 -118.5488,-118.4717 -177.7616,-177.7691 34.0834,100.1874 68.1667,200.375 102.25,300.5624 z" | |
719 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
720 | + <path | |
721 | + inkscape:connector-curvature="0" | |
722 | + id="rect5245-5-4-7-4-3-5-8-2-9-6" | |
723 | + d="m 6090.125,4947.4375 c 47.677,47.4093 94.9671,95.3478 142.7812,142.5313 12.3096,10.0651 31.7648,7.1628 41.4222,-5.2972 25.2023,-25.2247 50.4579,-50.3961 75.7341,-75.5466 -100.1875,-34.0729 -200.375,-68.1458 -300.5625,-102.2188 13.5417,13.5105 27.0833,27.0209 40.625,40.5313 z" | |
724 | + style="fill:#d38d5f;fill-opacity:1;stroke:none" /> | |
725 | + </g> | |
632 | 726 | </g> |
633 | 727 | <g |
634 | 728 | id="g4835" | ... | ... |
plugins/shopping_cart/public/style.css
1 | 1 | @import url(colorbox/colorbox.css); |
2 | 2 | |
3 | -.cart-add-item { | |
4 | - position: absolute; | |
5 | - right: 5px; | |
6 | - top: 5px; | |
3 | +.cart-add-item .ui-icon-cart { | |
4 | + background: url("images/button-icon.png") no-repeat scroll left center transparent; | |
5 | + width: 22px; | |
6 | + } | |
7 | + .cart-buy .ui-icon-cart { | |
8 | + background: url("images/button-icon.png") no-repeat scroll left center transparent; | |
9 | + width: 22px; | |
10 | + } | |
11 | +.cart-add-item .ui-button-text { | |
12 | + padding-left: 2.6em; | |
7 | 13 | } |
8 | 14 | |
9 | 15 | .product-item .cart-add-item { |
... | ... | @@ -13,16 +19,15 @@ |
13 | 19 | .cart { |
14 | 20 | position: fixed; |
15 | 21 | right: 20px; |
16 | - top: 0px; | |
22 | + bottom: 0px; | |
17 | 23 | width: 200px; |
18 | 24 | z-index: 1000; |
19 | 25 | border: 1px solid #777; |
20 | - border-top: none; | |
21 | - background: rgba(200,200,200,0.6); | |
26 | + background: rgba(100,100,100,0.8); | |
22 | 27 | } |
23 | 28 | |
24 | 29 | .cart h3 { |
25 | - color: #888; | |
30 | + color: #000; | |
26 | 31 | margin: 0px 0px 0px 5px; |
27 | 32 | } |
28 | 33 | |
... | ... | @@ -108,7 +113,7 @@ |
108 | 113 | padding: 0px 5px; |
109 | 114 | } |
110 | 115 | .cart-toggle:hover { |
111 | - color: #555; | |
116 | + color: #fff; | |
112 | 117 | } |
113 | 118 | |
114 | 119 | #cart-request-box { |
... | ... | @@ -120,6 +125,15 @@ |
120 | 125 | float: left; |
121 | 126 | } |
122 | 127 | |
128 | +#cart-request-box .cart-box-close { | |
129 | + position: absolute; | |
130 | + right: 10px; | |
131 | + bottom: 10px; | |
132 | + width: 16px; | |
133 | + height: 16px; | |
134 | + background-repeat: no-repeat; | |
135 | +} | |
136 | + | |
123 | 137 | #cart-form-main { |
124 | 138 | border: 2px solid #FFF; |
125 | 139 | padding: 0px 10px; |
... | ... | @@ -171,8 +185,8 @@ label.error { |
171 | 185 | |
172 | 186 | .controller-profile_editor a.control-panel-shopping-cart-purchase-report {background-image: url(images/control-panel/purchase-report.png)} |
173 | 187 | .controller-profile_editor .msie6 a.control-panel-shopping-cart-purchase-report {background-image: url(images/control-panel/purchase-report.gif)} |
174 | -.controller-profile_editor a.control-panel-shopping-cart {background-image: url(/images/control-panel/shopping-cart.png)} | |
175 | -.controller-profile_editor .msie6 a.control-panel-shopping-cart {background-image: url(/images/control-panel/shopping-cart.gif)} | |
188 | +.controller-profile_editor a.control-panel-shopping-cart-icon {background-image: url(images/control-panel/icon.png)} | |
189 | +.controller-profile_editor .msie6 a.control-panel-shopping-cart-icon {background-image: url(images/control-panel/icon.gif)} | |
176 | 190 | |
177 | 191 | .action-shopping_cart_plugin_myprofile-reports td.order-info { |
178 | 192 | padding: 0px; | ... | ... |
plugins/shopping_cart/views/cart.html.erb
1 | 1 | <div id="cart1" class="cart" style="display:none" |
2 | 2 | data-l10nRemoveItem="<%=_('Are you sure you want to remove this item?')%>" |
3 | - data-l10nCleanCart="<%=_('Are you sure you want to clean your cart?')%>"> | |
3 | + data-l10nCleanCart="<%=_('Are you sure you want to clean your basket?')%>"> | |
4 | 4 | <div class="cart-inner"> |
5 | 5 | <div class="cart-content"> |
6 | - <h3><%= _("Cart") %></h3> | |
7 | - <a href="cart:clean" onclick="Cart.clean(this); return false" class="cart-clean"><%=_('Clean cart')%></a> | |
6 | + <h3><%= _("Basket") %></h3> | |
7 | + <a href="cart:clean" onclick="Cart.clean(this); return false" class="cart-clean"><%=_('Clean basket')%></a> | |
8 | 8 | <ul class="cart-items"></ul> |
9 | 9 | <div class="cart-total"><%=_('Total:')%> <b></b></div> |
10 | 10 | <a href="cart:buy" class="cart-buy"><%=_('Shopping checkout')%></a> |
11 | 11 | </div> |
12 | 12 | <a href="#" onclick="Cart.toggle(this); return false" class="cart-toggle"> |
13 | - <span class="str-show"><%=_('Show cart')%></span> | |
14 | - <span class="str-hide" style="display:none"><%=_('Hide cart')%></span> | |
13 | + <span class="str-show"><%=_('Show basket')%></span> | |
14 | + <span class="str-hide" style="display:none"><%=_('Hide basket')%></span> | |
15 | 15 | </a> |
16 | 16 | </div> |
17 | 17 | </div> | ... | ... |
plugins/shopping_cart/views/shopping_cart_plugin_myprofile/edit.html.erb
plugins/shopping_cart/views/shopping_cart_plugin_profile/buy.html.erb
777 Bytes
public/javascripts/application.js
... | ... | @@ -255,7 +255,7 @@ function toggleSubmenu(trigger, title, link_list) { |
255 | 255 | if (!hide) { |
256 | 256 | var direction = 'down'; |
257 | 257 | if (submenu.hasClass('up')) direction = 'up'; |
258 | - submenu.show('slide', { 'direction' : direction }, 'slow'); | |
258 | + jQuery(submenu).fadeIn(); | |
259 | 259 | } |
260 | 260 | } |
261 | 261 | return false; |
... | ... | @@ -283,18 +283,18 @@ function toggleSubmenu(trigger, title, link_list) { |
283 | 283 | content.append(list); |
284 | 284 | submenu.append(header).append(content).append(footer); |
285 | 285 | jQuery(trigger).before(submenu); |
286 | - submenu.show('slide', { 'direction' : direction }, 'slow'); | |
286 | + jQuery(submenu).fadeIn(); | |
287 | 287 | } |
288 | 288 | |
289 | 289 | function toggleMenu(trigger) { |
290 | 290 | hideAllSubmenus(); |
291 | - jQuery(trigger).siblings('.simplemenu-submenu').toggle('slide', {direction: 'up'}, 'slow').toggleClass('opened'); | |
291 | + jQuery(trigger).siblings('.simplemenu-submenu').toggle().toggleClass('opened'); | |
292 | 292 | } |
293 | 293 | |
294 | 294 | function hideAllSubmenus() { |
295 | - jQuery('.menu-submenu.up:visible').hide('slide', { 'direction' : 'up' }, 'slow'); | |
296 | - jQuery('.simplemenu-submenu:visible').hide('slide', { 'direction' : 'up' }, 'slow').toggleClass('opened'); | |
297 | - jQuery('.menu-submenu.down:visible').hide('slide', { 'direction' : 'down' }, 'slow'); | |
295 | + jQuery('.menu-submenu.up:visible').fadeOut('slow'); | |
296 | + jQuery('.simplemenu-submenu:visible').hide().toggleClass('opened'); | |
297 | + jQuery('.menu-submenu.down:visible').fadeOut('slow'); | |
298 | 298 | jQuery('#chat-online-users-content').hide(); |
299 | 299 | } |
300 | 300 | |
... | ... | @@ -694,3 +694,14 @@ jQuery(function() { |
694 | 694 | target: "#ajax-form-message-area" |
695 | 695 | }) |
696 | 696 | }); |
697 | + | |
698 | +// from http://jsfiddle.net/naveen/HkxJg/ | |
699 | +// Function to get the Max value in Array | |
700 | +Array.max = function(array) { | |
701 | + return Math.max.apply(Math, array); | |
702 | +}; | |
703 | +// Function to get the Min value in Array | |
704 | +Array.min = function(array) { | |
705 | + return Math.min.apply(Math, array); | |
706 | +}; | |
707 | + | ... | ... |
... | ... | @@ -0,0 +1,47 @@ |
1 | +(function($) { | |
2 | + | |
3 | +$('#product-list .product .expand-box').live('click', function () { | |
4 | + $('.expand-box').each(function(index, element){ this.clicked = false; toggle_expandbox(this); }); | |
5 | + this.clicked = !this.clicked; | |
6 | + toggle_expandbox(this); | |
7 | + $.each($(this).siblings('.expand-box'), function(index, value) { value.clicked = false; toggle_expandbox(value); }); | |
8 | + | |
9 | + return false; | |
10 | +}); | |
11 | + | |
12 | +$(document).live('click', function() { | |
13 | + $.each($('#product-list .product .expand-box'), function(index, value) { value.clicked = false; toggle_expandbox(value); }); | |
14 | +}); | |
15 | + | |
16 | +$(document).click(function (event) { | |
17 | + if ($(event.target).parents('.expand-box').length == 0) { | |
18 | + $('.expand-box').each(function(index, element){ | |
19 | + $(element).removeClass('open'); | |
20 | + $(element).children('div').toggle(false); | |
21 | + }); | |
22 | + } | |
23 | +}); | |
24 | + | |
25 | +var rows = {}; | |
26 | +$('#product-list .product').each(function (index, element) { | |
27 | + obj = rows[$(element).offset().top] || {}; | |
28 | + | |
29 | + obj.heights = obj.heights || []; | |
30 | + obj.elements = obj.elements || []; | |
31 | + obj.heights.push($(element).height()); | |
32 | + obj.elements.push(element); | |
33 | + | |
34 | + rows[$(element).offset().top] = obj; | |
35 | +}); | |
36 | + | |
37 | +$.each(rows, function(top, obj) { | |
38 | + maxWidth = Array.max(obj.heights); | |
39 | + $(obj.elements).height(maxWidth); | |
40 | +}); | |
41 | + | |
42 | +})(jQuery); | |
43 | + | |
44 | +function toggle_expandbox(e) { | |
45 | + jQuery(e).toggleClass('open', e.clicked); | |
46 | + jQuery(e).children('div').toggle(e.clicked).css({left: jQuery(e).position().left-180, top: jQuery(e).position().top-10}); | |
47 | +} | ... | ... |
... | ... | @@ -0,0 +1,183 @@ |
1 | +(function($) { | |
2 | + | |
3 | + $("#manage-product-details-button").live('click', function() { | |
4 | + $("#product-price-details").find('.loading-area').addClass('small-loading'); | |
5 | + url = $(this).attr('href'); | |
6 | + $.get(url, function(data){ | |
7 | + $("#manage-product-details-button").hide(); | |
8 | + $("#display-price-details").hide(); | |
9 | + $("#display-manage-price-details").html(data); | |
10 | + $("#product-price-details").find('.loading-area').removeClass('small-loading'); | |
11 | + }); | |
12 | + return false; | |
13 | + }); | |
14 | + | |
15 | + $(".cancel-price-details").live('click', function() { | |
16 | + if ( !$(this).hasClass('form-changed') ) { | |
17 | + cancelPriceDetailsEdition(); | |
18 | + } else { | |
19 | + if (confirm($(this).attr('data-confirm'))) { | |
20 | + cancelPriceDetailsEdition(); | |
21 | + } | |
22 | + } | |
23 | + return false; | |
24 | + }); | |
25 | + | |
26 | + $("#manage-product-details-form").live('submit', function(data) { | |
27 | + var form = this; | |
28 | + $(form).find('.loading-area').addClass('small-loading'); | |
29 | + $(form).css('cursor', 'progress'); | |
30 | + $.post(form.action, $(form).serialize(), function(data) { | |
31 | + $("#display-manage-price-details").html(data); | |
32 | + $("#manage-product-details-button").show(); | |
33 | + }); | |
34 | + if ($('#progressbar-icon').hasClass('ui-icon-check')) { | |
35 | + display_notice($('#progressbar-icon').attr('data-price-described-notice')); | |
36 | + } | |
37 | + return false; | |
38 | + }); | |
39 | + | |
40 | + $("#add-new-cost").live('click', function() { | |
41 | + $('#display-product-price-details tbody').append($('#new-cost-fields tbody').html()); | |
42 | + return false; | |
43 | + }); | |
44 | + | |
45 | + $(".cancel-new-cost").live('click', function() { | |
46 | + $(this).parents('tr').remove(); | |
47 | + calculateValuesForBar(); | |
48 | + return false; | |
49 | + }); | |
50 | + | |
51 | + $("#product-info-form").live('submit', function(data) { | |
52 | + var form = this; | |
53 | + updatePriceCompositionBar(form); | |
54 | + }); | |
55 | + | |
56 | + $("form.edit_input").live('submit', function(data) { | |
57 | + var form = this; | |
58 | + inputs_cost_update_url = $(form).find('#inputs-cost-update-url').val(); | |
59 | + $.get(inputs_cost_update_url, function(data){ | |
60 | + $(".inputs-cost span").html(data); | |
61 | + }); | |
62 | + updatePriceCompositionBar(form); | |
63 | + return false; | |
64 | + }); | |
65 | + | |
66 | + $("#manage-product-details-form .price-details-price").live('blur', function(data) { calculateValuesForBar(); }); | |
67 | + | |
68 | + function cancelPriceDetailsEdition() { | |
69 | + $("#manage-product-details-button").show(); | |
70 | + $("#display-price-details").show(); | |
71 | + $("#display-manage-price-details").html(''); | |
72 | + }; | |
73 | + | |
74 | +})(jQuery); | |
75 | + | |
76 | +function updatePriceCompositionBar(form) { | |
77 | + bar_url = jQuery(form).find('.bar-update-url').val(); | |
78 | + jQuery.ajax({ | |
79 | + url : bar_url, | |
80 | + success : function(data) { | |
81 | + jQuery("#price-composition-bar").html(data); | |
82 | + }, | |
83 | + complete : function() { | |
84 | + jQuery('form #product_price').val(currencyToFloat(jQuery('#progressbar-text .product_price').html(), currency_format.separator, currency_format.delimiter)); | |
85 | + jQuery('form #product_inputs_cost').val(currencyToFloat(jQuery('#display-product-price-details .inputs-cost span').html(), currency_format.separator, currency_format.delimiter, currency_format.unit)); | |
86 | + calculateValuesForBar(); | |
87 | + } | |
88 | + }); | |
89 | +}; | |
90 | + | |
91 | +function enablePriceDetailSubmit() { | |
92 | + jQuery('#manage-product-details-form input.submit').removeAttr("disabled").removeClass('disabled'); | |
93 | +} | |
94 | + | |
95 | +function calculateValuesForBar() { | |
96 | + jQuery('.cancel-price-details').addClass('form-changed'); | |
97 | + var product_price = parseFloat(jQuery('form #product_price').val()); | |
98 | + var total_cost = parseFloat(jQuery('form #product_inputs_cost').val()); | |
99 | + | |
100 | + jQuery('form .price-details-price').each(function() { | |
101 | + var this_val = parseFloat(jQuery(this).val().replace(currency_format.separator, '.')) || 0; | |
102 | + total_cost = total_cost + this_val; | |
103 | + }); | |
104 | + enablePriceDetailSubmit(); | |
105 | + | |
106 | + var described = (product_price - total_cost) == 0; | |
107 | + var percentage = total_cost * 100 / product_price; | |
108 | + priceCompositionBar(percentage, described, total_cost, product_price); | |
109 | +} | |
110 | + | |
111 | +function addCommas(nStr) { | |
112 | + nStr += ''; | |
113 | + var x = nStr.split('.'); | |
114 | + var x1 = x[0]; | |
115 | + var x2 = x.length > 1 ? '.' + x[1] : ''; | |
116 | + var rgx = /(\d+)(\d{3})/; | |
117 | + while (rgx.test(x1)) { | |
118 | + x1 = x1.replace(rgx, '$1' + ',' + '$2'); | |
119 | + } | |
120 | + return x1 + x2; | |
121 | +} | |
122 | + | |
123 | +function floatToCurrency(value, sep, del, cur) { | |
124 | + var ret = ''; | |
125 | + if (cur) ret = cur + ' '; | |
126 | + if (!sep) sep = '.'; | |
127 | + if (!del) del = ','; | |
128 | + return ret + addCommas(parseFloat(value).toFixed(2).toString()).replace('.', '%sep%').replace(',', del).replace('%sep%', sep); | |
129 | +} | |
130 | + | |
131 | +function currencyToFloat(value, sep, del, cur) { | |
132 | + var val = value; | |
133 | + if (cur) val = val.replace(cur + ' ', ''); | |
134 | + if (!sep) sep = '.'; | |
135 | + if (!del) del = ','; | |
136 | + return parseFloat(val.replace(del, '').replace(sep, '.')); | |
137 | +} | |
138 | + | |
139 | +function productionCostTypeChange(select, url, question, error_msg) { | |
140 | + if (select.value == '') { | |
141 | + var newType = prompt(question); | |
142 | + if (newType) { | |
143 | + jQuery.ajax({ | |
144 | + url: url + "/" + newType, | |
145 | + dataType: 'json', | |
146 | + success: function(data, status, ajax){ | |
147 | + if (data.ok) { | |
148 | + var opt = jQuery('<option value="' + data.id + '">' + newType + '</option>'); | |
149 | + opt.insertBefore(jQuery("option:last", select)); | |
150 | + select.selectedIndex = select.options.length - 2; | |
151 | + opt.clone().insertBefore('#new-cost-fields .production-cost-selection option:last'); | |
152 | + } else { | |
153 | + alert(data.error_msg); | |
154 | + } | |
155 | + }, | |
156 | + error: function(ajax, status, error){ | |
157 | + alert(error_msg); | |
158 | + } | |
159 | + }); | |
160 | + } | |
161 | + } | |
162 | +} | |
163 | + | |
164 | +function priceCompositionBar(value, described, total_cost, price) { | |
165 | + jQuery(function($) { | |
166 | + var bar_area = $('#price-composition-bar'); | |
167 | + $(bar_area).find('#progressbar').progressbar({ | |
168 | + value: value | |
169 | + }); | |
170 | + $(bar_area).find('.production_cost').html(floatToCurrency(total_cost, currency_format.separator, currency_format.delimiter)); | |
171 | + $(bar_area).find('.product_price').html(floatToCurrency(price, currency_format.separator, currency_format.delimiter)); | |
172 | + if (described) { | |
173 | + $(bar_area).find('#progressbar-icon').addClass('ui-icon-check'); | |
174 | + $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-described-message')); | |
175 | + $(bar_area).find('div.ui-progressbar-value').addClass('price-described'); | |
176 | + } else { | |
177 | + $(bar_area).find('#progressbar-icon').removeClass('ui-icon-check'); | |
178 | + $(bar_area).find('#progressbar-icon').attr('title', $('#progressbar-icon').attr('data-price-not-described-message')); | |
179 | + $(bar_area).find('div.ui-progressbar-value').removeClass('price-described'); | |
180 | + | |
181 | + } | |
182 | + }); | |
183 | +} | ... | ... |
public/stylesheets/application.css
... | ... | @@ -1075,10 +1075,12 @@ code input { |
1075 | 1075 | text-align: left; |
1076 | 1076 | background: transparent url(/images/black-alpha-pixel.png); |
1077 | 1077 | border-bottom: 1px solid #333; |
1078 | + text-decoration: none; | |
1078 | 1079 | } |
1079 | 1080 | |
1080 | 1081 | .zoomable-image:hover .zoomify-image { |
1081 | 1082 | display: block; |
1083 | + text-decoration: none; | |
1082 | 1084 | } |
1083 | 1085 | |
1084 | 1086 | #article .zoomify-image { |
... | ... | @@ -1093,6 +1095,7 @@ code input { |
1093 | 1095 | border-bottom: 1px solid #eee; |
1094 | 1096 | display: block; |
1095 | 1097 | background: transparent url(/images/zoom.png) left center no-repeat; |
1098 | + color: #fff; | |
1096 | 1099 | } |
1097 | 1100 | |
1098 | 1101 | #article pre { |
... | ... | @@ -2962,71 +2965,228 @@ div#activation_enterprise div { |
2962 | 2965 | |
2963 | 2966 | /* ==> public/stylesheets/controller_catalog.css <== */ |
2964 | 2967 | /* ==> @import url('products.css'); <== */ |
2968 | +/* * * Products catalog * * * * * * * * * * * * */ | |
2965 | 2969 | |
2966 | -/* * * List Products * * * * * * * * * * * * */ | |
2967 | - | |
2968 | -#product_list { | |
2970 | +#product-list { | |
2971 | + line-height: 20px; | |
2969 | 2972 | margin: 0px; |
2970 | 2973 | padding: 0px; |
2971 | 2974 | } |
2972 | - | |
2973 | -#product_list ul { | |
2975 | +#product-list ul { | |
2974 | 2976 | margin: 0px; |
2975 | 2977 | padding: 0px; |
2976 | 2978 | } |
2977 | - | |
2978 | -#content #product_list li { | |
2979 | +#product-list li { | |
2979 | 2980 | margin: 0px; |
2980 | 2981 | padding: 0px; |
2981 | 2982 | list-style: none; |
2982 | 2983 | } |
2983 | - | |
2984 | -#content #product_list li.product { | |
2985 | - border: 1px solid #888; | |
2984 | +#product-list li.product { | |
2985 | + width: 200px; | |
2986 | + min-height: 280px; | |
2987 | + float: left; | |
2988 | + padding: 10px 30px 10px 0; | |
2986 | 2989 | margin-bottom: 10px; |
2987 | - padding: 5px 10px; | |
2988 | - position: relative; | |
2989 | 2990 | } |
2990 | - | |
2991 | -#product_list .product-pic { | |
2991 | +#product-list .expand-box:hover { | |
2992 | + background-color: #28F091; | |
2993 | +} | |
2994 | +#product-list .expand-box { | |
2995 | + background-color: #1EB46D; | |
2996 | + margin-bottom: 3px; | |
2997 | + -moz-border-radius: 10px 0px 0px 10px; | |
2998 | + -webkit-border-radius: 10px 0px 0px 10px; | |
2999 | + border-radius: 10px 0px 0px 10px; | |
3000 | + width: 202px; | |
3001 | +} | |
3002 | +#product-list .expand-box > span { | |
3003 | + padding-left: 20px; | |
3004 | + font-size: 0.70em; | |
3005 | + color: white; | |
3006 | + font-weight: bold; | |
3007 | + background: url(/images/catalog-expanders.png) no-repeat; | |
2992 | 3008 | display: block; |
2993 | - width: 64px; | |
2994 | - height: 64px; | |
2995 | - background-repeat: no-repeat; | |
2996 | - background-position: 50% 50%; | |
3009 | + line-height: 15px; | |
3010 | + background-position: left 100%; | |
3011 | + cursor: pointer; | |
3012 | +} | |
3013 | +#product-list .expand-box.open > span { | |
3014 | + background-position: left top; | |
3015 | +} | |
3016 | +#product-list .expand-box-corner { | |
3017 | +} | |
3018 | +#product-list li.product .product-qualifiers { | |
3019 | + font-size: 9px; | |
3020 | + line-height: normal; | |
3021 | +} | |
3022 | +#product-list li.product .product-qualifiers > span { | |
3023 | + font-weight: bold; | |
3024 | + display: block; | |
3025 | + margin-top: 8px; | |
3026 | +} | |
3027 | +#product-list li.product .product-qualifiers > span, | |
3028 | +#product-list li.product .expand-box > span { | |
3029 | + text-transform: uppercase; | |
3030 | +} | |
3031 | +#product-list li.product .expand-box > div { | |
3032 | + display: none; | |
3033 | + position: absolute; | |
3034 | + z-index: 10; | |
3035 | +} | |
3036 | +#product-list li.product .expand-box .content { | |
3037 | + font-size: 11px; | |
3038 | + padding: 6px 5px; | |
3039 | + overflow: auto; | |
3040 | + max-height: 200px; | |
3041 | + width: 160px; | |
3042 | + border-radius: 5px; | |
3043 | + -moz-border-radius: 5px; | |
3044 | + -webkit-border-radius: 5px; | |
3045 | + background: #DCFFD7; | |
3046 | + border: 2px solid #1EB46D; | |
3047 | + min-height: 30px; | |
2997 | 3048 | float: left; |
2998 | - margin-right: 15px; | |
2999 | - position: relative; /* work arround msie bug */ | |
3049 | + text-align: left; | |
3050 | +} | |
3051 | +#product-list li.product .expand-box .arrow { | |
3052 | + border-left: 6px solid #1EB46D; | |
3053 | + border-top: 5px solid transparent; | |
3054 | + border-bottom: 5px solid transparent; | |
3055 | + margin-top: 13px; | |
3056 | + float: right; | |
3000 | 3057 | } |
3001 | 3058 | |
3002 | -#product_list .product-pic span { | |
3003 | - display: none; | |
3059 | +#product-list li.product.not-available .expand-box { | |
3060 | + background-color: #DCF3E9; | |
3061 | +} | |
3062 | +#product-list li.product.not-available .product-link a, | |
3063 | +#product-list li.product.not-available .product-qualifiers, | |
3064 | +#product-list li.product.not-available .product-price-line, | |
3065 | +#product-list li.product.not-available .product-price, | |
3066 | +#product-list li.product.not-available .product-unit { | |
3067 | + color: #ACACAC !important; | |
3068 | +} | |
3069 | +#product-list .product-link { | |
3070 | + margin-top: 5px; | |
3071 | + margin-bottom: 5px; | |
3072 | + color: #006672; | |
3073 | + font-weight: bold; | |
3074 | + text-align: left; | |
3075 | +} | |
3076 | +#product-list .prop { | |
3077 | + float:right; | |
3078 | + width:1px; | |
3079 | +} | |
3080 | +#product-list .min50px { | |
3081 | + height:50px; | |
3082 | +} | |
3083 | +#product-list .product-row-clear { | |
3084 | + clear:both; | |
3085 | + height:1px; | |
3086 | + overflow:hidden; | |
3004 | 3087 | } |
3005 | 3088 | |
3006 | -#content #product_list h3 { | |
3007 | - margin: 0px; | |
3008 | - padding: 0px; | |
3009 | - font-size: 120%; | |
3089 | +#product-list .product-price-line { | |
3090 | + margin: 0 0 8px; | |
3091 | + display: block; | |
3092 | + clear: both; | |
3010 | 3093 | } |
3011 | -.msie #content #product_list h3 { | |
3012 | - margin-top: -15px; | |
3094 | +#product-list .product-price { | |
3095 | + font-weight: bold; | |
3013 | 3096 | } |
3014 | -#product_list h3 a { | |
3015 | - text-decoration: none; | |
3097 | +#product-list .product-price, | |
3098 | +#product-list .product-unit { | |
3099 | + color: #0194C7; | |
3100 | +} | |
3101 | +#product-list .product-unit, | |
3102 | +#product-list .product-discount, | |
3103 | +#product-list .product-discount-by { | |
3104 | + font-size: 9px; | |
3105 | + margin-right: 3px; | |
3106 | +} | |
3107 | +#product-list .product-discount, | |
3108 | +#product-list .product-price { | |
3109 | + float: left; | |
3110 | + line-height: 15px; | |
3111 | + margin-right: 3px; | |
3112 | +} | |
3113 | +#product-list .product-discount span { | |
3114 | + text-decoration: line-through; | |
3115 | +} | |
3116 | +#product-list .product-discount-by { | |
3117 | + text-decoration: none !important; | |
3016 | 3118 | } |
3017 | 3119 | |
3018 | -#product_list .product_category { | |
3019 | - font-size: 11px; | |
3120 | +#product-list .search-product-input-dots-to-price { | |
3121 | + width: 100%; | |
3122 | + margin: 0; | |
3123 | +} | |
3124 | +#product-list .search-product-input-name { | |
3125 | + background-color: #DCFFD7; | |
3126 | + max-width: 101px; | |
3127 | +} | |
3128 | +#product-list .search-product-input-price { | |
3129 | + background-color: #DCFFD7; | |
3020 | 3130 | } |
3021 | 3131 | |
3022 | -#product_list .description { | |
3023 | - clear: left; | |
3024 | - font-size: 11px; | |
3025 | - text-align: justify; | |
3026 | - padding: 5px 10px 0px 10px; | |
3132 | +#product-list .catalog-item-extras { | |
3133 | + position: absolute; | |
3134 | + bottom: 0px; | |
3135 | + right: 0px; | |
3136 | +} | |
3137 | +#product-list .product-big { | |
3138 | + background-repeat: no-repeat; | |
3139 | + background-position: 50% 50%; | |
3140 | + display: block; | |
3141 | + width: 200px; | |
3142 | + height: 160px; | |
3143 | +} | |
3144 | +#product-list .ui-button { | |
3145 | + margin: 0; | |
3146 | +} | |
3147 | +#product-list .ui-button-text { | |
3148 | + color: #D38D5F; | |
3149 | + font-size: 0.8em; | |
3150 | + padding: 0.1em 0.3em 0.1em 3em; | |
3151 | +} | |
3152 | +#product-list .product-big span { | |
3153 | + display: none; | |
3154 | +} | |
3155 | +#product-list .product-image-link { | |
3156 | + position: relative; | |
3157 | + width: 200px; | |
3158 | + height: 160px; | |
3159 | + border: 1px solid #BFBFBF; | |
3160 | + position: relative; /* work arround msie bug */ | |
3161 | + text-align: center; | |
3162 | + vertical-align: middle; | |
3027 | 3163 | } |
3028 | -.msie #product_list .description { | |
3029 | - padding: 5px 10px 10px 10px; | |
3164 | +#product-list .product-image-link .no-image { | |
3165 | + line-height: 145px; | |
3166 | + text-align: center; | |
3167 | + color: #777; | |
3168 | + font-size: 9px; | |
3169 | + font-weight: bold; | |
3170 | + text-transform: uppercase; | |
3171 | + letter-spacing: 1px; | |
3172 | + user-select: none; | |
3173 | + -moz-user-select: none; | |
3174 | + -khtml-user-select: none; | |
3175 | + -webkit-user-select: none; | |
3176 | +} | |
3177 | +#product-list li.product-unavailable { | |
3178 | + text-transform: uppercase; | |
3179 | + color: #FF6261; | |
3180 | + font-weight: bold; | |
3181 | + line-height: 40px; | |
3182 | +} | |
3183 | +#product-list h3 { | |
3184 | + margin: 0px; | |
3185 | + padding: 0px; | |
3186 | + font-size: 120%; | |
3187 | +} | |
3188 | +.msie #product-list h3 { | |
3189 | + margin-top: -15px; | |
3030 | 3190 | } |
3031 | 3191 | |
3032 | 3192 | /* * * Show Product * * * * * * * * * * * * */ |
... | ... | @@ -3223,6 +3383,86 @@ div#activation_enterprise div { |
3223 | 3383 | font-weight: bold; |
3224 | 3384 | } |
3225 | 3385 | |
3386 | +/* * * * * * Price details * * * * * */ | |
3387 | + | |
3388 | +#display-price-details .price-details-list { | |
3389 | + padding-left: 0px; | |
3390 | +} | |
3391 | + | |
3392 | +#display-price-details .price-details-list li { | |
3393 | + list-style: none; | |
3394 | +} | |
3395 | + | |
3396 | +#display-price-details .price-details-list li .price-detail-name { | |
3397 | + width: 200px; | |
3398 | +} | |
3399 | + | |
3400 | +#display-price-details .price-details-list li .price-detail-name, | |
3401 | +#display-price-details .price-details-list li .price-detail-price { | |
3402 | + display: inline-block; | |
3403 | +} | |
3404 | + | |
3405 | +#manage-product-details-form .formlabel, | |
3406 | +#manage-product-details-form .formfield { | |
3407 | + display: inline-block; | |
3408 | +} | |
3409 | + | |
3410 | +#manage-product-details-form #add-new-cost { | |
3411 | + float: right; | |
3412 | +} | |
3413 | + | |
3414 | +/* * * Progress bar on price details edition * * */ | |
3415 | + | |
3416 | +#display-manage-price-details .ui-widget-content { | |
3417 | + border: 1px solid #DDD; | |
3418 | +} | |
3419 | + | |
3420 | +#display-manage-price-details .ui-progressbar { | |
3421 | + height: 20px; | |
3422 | +} | |
3423 | + | |
3424 | +#display-manage-price-details .ui-progressbar .ui-progressbar-value { | |
3425 | + margin: 0px; | |
3426 | + background-color: #A40000; | |
3427 | + filter:alpha(opacity=70); | |
3428 | + -moz-opacity: 0.7; | |
3429 | + opacity: 0.7; | |
3430 | +} | |
3431 | + | |
3432 | +#display-manage-price-details .ui-progressbar .ui-progressbar-value.price-described { | |
3433 | + background-color: #4E9A06; | |
3434 | +} | |
3435 | + | |
3436 | +#display-manage-price-details #price-details-info { | |
3437 | + margin: 10px 0px; | |
3438 | +} | |
3439 | + | |
3440 | +#display-manage-price-details #details-progressbar { | |
3441 | + position: relative; | |
3442 | + width: 410px; | |
3443 | + display: inline-block; | |
3444 | +} | |
3445 | + | |
3446 | +#display-manage-price-details #progressbar-text { | |
3447 | + position: absolute; | |
3448 | + top: 5px; | |
3449 | + right: 7px; | |
3450 | + font-size: 11px; | |
3451 | +} | |
3452 | + | |
3453 | +#display-manage-price-details #progressbar-icon { | |
3454 | + display: inline-block; | |
3455 | + cursor: pointer; | |
3456 | +} | |
3457 | + | |
3458 | +#display-manage-price-details #details-progressbar .ui-corner-left, | |
3459 | +#display-manage-price-details #details-progressbar .ui-corner-right { | |
3460 | + -moz-border-radius-bottomleft: 0px; | |
3461 | + -moz-border-radius-bottomright: 0px; | |
3462 | + -moz-border-radius-topleft: 0px; | |
3463 | + -moz-border-radius-topright: 0px; | |
3464 | +} | |
3465 | + | |
3226 | 3466 | /* ==> public/stylesheets/controller_cms.css <== */ |
3227 | 3467 | |
3228 | 3468 | ... | ... |
public/stylesheets/colorbox/colorbox.css
... | ... | @@ -18,29 +18,29 @@ |
18 | 18 | Change the following styles to modify the appearance of ColorBox. They are |
19 | 19 | ordered & tabbed in a way that represents the nesting of the generated HTML. |
20 | 20 | */ |
21 | -#cboxOverlay{background:url(images/overlay.png) repeat 0 0;} | |
21 | +#cboxOverlay{background:url(/stylesheets/colorbox/images/overlay.png) repeat 0 0;} | |
22 | 22 | #colorbox{} |
23 | - #cboxTopLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -100px 0;} | |
24 | - #cboxTopRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -129px 0;} | |
25 | - #cboxBottomLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -100px -29px;} | |
26 | - #cboxBottomRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -129px -29px;} | |
27 | - #cboxMiddleLeft{width:21px; background:url(images/controls.png) left top repeat-y;} | |
28 | - #cboxMiddleRight{width:21px; background:url(images/controls.png) right top repeat-y;} | |
29 | - #cboxTopCenter{height:21px; background:url(images/border.png) 0 0 repeat-x;} | |
30 | - #cboxBottomCenter{height:21px; background:url(images/border.png) 0 -29px repeat-x;} | |
23 | + #cboxTopLeft{width:21px; height:21px; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -100px 0;} | |
24 | + #cboxTopRight{width:21px; height:21px; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -129px 0;} | |
25 | + #cboxBottomLeft{width:21px; height:21px; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -100px -29px;} | |
26 | + #cboxBottomRight{width:21px; height:21px; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -129px -29px;} | |
27 | + #cboxMiddleLeft{width:21px; background:url(/stylesheets/colorbox/images/controls.png) left top repeat-y;} | |
28 | + #cboxMiddleRight{width:21px; background:url(/stylesheets/colorbox/images/controls.png) right top repeat-y;} | |
29 | + #cboxTopCenter{height:21px; background:url(/stylesheets/colorbox/images/border.png) 0 0 repeat-x;} | |
30 | + #cboxBottomCenter{height:21px; background:url(/stylesheets/colorbox/images/border.png) 0 -29px repeat-x;} | |
31 | 31 | #cboxContent{background:#fff; overflow:hidden;} |
32 | 32 | #cboxError{padding:50px; border:1px solid #ccc;} |
33 | 33 | #cboxLoadedContent{margin-bottom:28px;} |
34 | 34 | #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} |
35 | 35 | #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} |
36 | 36 | #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;} |
37 | - #cboxPrevious{position:absolute; bottom:0; left:0; background:url(images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;} | |
37 | + #cboxPrevious{position:absolute; bottom:0; left:0; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;} | |
38 | 38 | #cboxPrevious.hover{background-position:-75px -25px;} |
39 | - #cboxNext{position:absolute; bottom:0; left:27px; background:url(images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;} | |
39 | + #cboxNext{position:absolute; bottom:0; left:27px; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;} | |
40 | 40 | #cboxNext.hover{background-position:-50px -25px;} |
41 | - #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;} | |
42 | - #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;} | |
43 | - #cboxClose{position:absolute; bottom:0; right:0; background:url(images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;} | |
41 | + #cboxLoadingOverlay{background:url(/stylesheets/colorbox/images/loading_background.png) no-repeat center center;} | |
42 | + #cboxLoadingGraphic{background:url(/stylesheets/colorbox/images/loading.gif) no-repeat center center;} | |
43 | + #cboxClose{position:absolute; bottom:0; right:0; background:url(/stylesheets/colorbox/images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;} | |
44 | 44 | #cboxClose.hover{background-position:-25px -25px;} |
45 | 45 | |
46 | 46 | /* |
... | ... | @@ -61,14 +61,14 @@ |
61 | 61 | /* |
62 | 62 | The following provides PNG transparency support for IE6 |
63 | 63 | */ |
64 | -.cboxIE6 #cboxTopLeft{background:url(images/ie6/borderTopLeft.png);} | |
65 | -.cboxIE6 #cboxTopCenter{background:url(images/ie6/borderTopCenter.png);} | |
66 | -.cboxIE6 #cboxTopRight{background:url(images/ie6/borderTopRight.png);} | |
67 | -.cboxIE6 #cboxBottomLeft{background:url(images/ie6/borderBottomLeft.png);} | |
68 | -.cboxIE6 #cboxBottomCenter{background:url(images/ie6/borderBottomCenter.png);} | |
69 | -.cboxIE6 #cboxBottomRight{background:url(images/ie6/borderBottomRight.png);} | |
70 | -.cboxIE6 #cboxMiddleLeft{background:url(images/ie6/borderMiddleLeft.png);} | |
71 | -.cboxIE6 #cboxMiddleRight{background:url(images/ie6/borderMiddleRight.png);} | |
64 | +.cboxIE6 #cboxTopLeft{background:url(/stylesheets/colorbox/images/ie6/borderTopLeft.png);} | |
65 | +.cboxIE6 #cboxTopCenter{background:url(/stylesheets/colorbox/images/ie6/borderTopCenter.png);} | |
66 | +.cboxIE6 #cboxTopRight{background:url(/stylesheets/colorbox/images/ie6/borderTopRight.png);} | |
67 | +.cboxIE6 #cboxBottomLeft{background:url(/stylesheets/colorbox/images/ie6/borderBottomLeft.png);} | |
68 | +.cboxIE6 #cboxBottomCenter{background:url(/stylesheets/colorbox/images/ie6/borderBottomCenter.png);} | |
69 | +.cboxIE6 #cboxBottomRight{background:url(/stylesheets/colorbox/images/ie6/borderBottomRight.png);} | |
70 | +.cboxIE6 #cboxMiddleLeft{background:url(/stylesheets/colorbox/images/ie6/borderMiddleLeft.png);} | |
71 | +.cboxIE6 #cboxMiddleRight{background:url(/stylesheets/colorbox/images/ie6/borderMiddleRight.png);} | |
72 | 72 | |
73 | 73 | .cboxIE6 #cboxTopLeft, |
74 | 74 | .cboxIE6 #cboxTopCenter, | ... | ... |
script/sample-profiles
test/factories.rb
... | ... | @@ -449,4 +449,12 @@ module Noosfero::Factory |
449 | 449 | { :singular => 'Litre', :plural => 'Litres', :environment_id => 1 } |
450 | 450 | end |
451 | 451 | |
452 | + ############################################### | |
453 | + # Production Cost | |
454 | + ############################################### | |
455 | + | |
456 | + def defaults_for_production_cost | |
457 | + { :name => 'Production cost ' + factory_num_seq.to_s } | |
458 | + end | |
459 | + | |
452 | 460 | end | ... | ... |
13.4 KB
17.2 KB
test/functional/catalog_controller_test.rb
... | ... | @@ -46,7 +46,7 @@ class CatalogControllerTest < ActionController::TestCase |
46 | 46 | |
47 | 47 | assert_equal 12, @enterprise.products.count |
48 | 48 | get :index, :profile => @enterprise.identifier |
49 | - assert_equal 10, assigns(:products).count | |
49 | + assert_equal 9, assigns(:products).count | |
50 | 50 | assert_tag :a, :attributes => {:class => 'next_page'} |
51 | 51 | end |
52 | 52 | |
... | ... | @@ -63,21 +63,13 @@ class CatalogControllerTest < ActionController::TestCase |
63 | 63 | should 'not show product price when listing products if not informed' do |
64 | 64 | prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) |
65 | 65 | get :index, :profile => @enterprise.identifier |
66 | - assert_no_tag :tag => 'li', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
66 | + assert_no_tag :tag => 'span', :attributes => { :class => 'product-price with-discount' }, :content => /50.00/ | |
67 | 67 | end |
68 | 68 | |
69 | 69 | should 'show product price when listing products if informed' do |
70 | 70 | prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category) |
71 | 71 | get :index, :profile => @enterprise.identifier |
72 | - assert_tag :tag => 'li', :attributes => { :class => 'product_price' }, :content => /Price:/ | |
73 | - end | |
74 | - | |
75 | - should 'link to assets products wiht product category in the link to product category on index' do | |
76 | - pc = ProductCategory.create!(:name => 'some product', :environment => enterprise.environment) | |
77 | - prod = enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => pc) | |
78 | - | |
79 | - get :index, :profile => enterprise.identifier | |
80 | - assert_tag :tag => 'a', :attributes => {:href => /assets\/products\?product_category=#{pc.id}/} | |
72 | + assert_tag :tag => 'span', :attributes => { :class => 'product-price with-discount' }, :content => /50.00/ | |
81 | 73 | end |
82 | 74 | |
83 | 75 | should 'add an zero width space every 4 caracters of comment urls' do | ... | ... |
test/functional/manage_products_controller_test.rb
... | ... | @@ -468,4 +468,47 @@ class ManageProductsControllerTest < ActionController::TestCase |
468 | 468 | assert_response 403 |
469 | 469 | end |
470 | 470 | |
471 | + should 'remove price detail of a product' do | |
472 | + product = fast_create(Product, :enterprise_id => @enterprise.id, :product_category_id => @product_category.id) | |
473 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
474 | + detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
475 | + | |
476 | + assert_equal [detail], product.price_details | |
477 | + | |
478 | + post :remove_price_detail, :id => detail.id, :product => product, :profile => @enterprise.identifier | |
479 | + product.reload | |
480 | + assert_equal [], product.price_details | |
481 | + end | |
482 | + | |
483 | + should 'create a production cost for enterprise' do | |
484 | + get :create_production_cost, :profile => @enterprise.identifier, :id => 'Taxes' | |
485 | + | |
486 | + assert_equal ['Taxes'], Enterprise.find(@enterprise.id).production_costs.map(&:name) | |
487 | + resp = ActiveSupport::JSON.decode(@response.body) | |
488 | + assert_equal 'Taxes', resp['name'] | |
489 | + assert resp['id'].kind_of?(Integer) | |
490 | + assert resp['ok'] | |
491 | + assert_nil resp['error_msg'] | |
492 | + end | |
493 | + | |
494 | + should 'display error if production cost has no name' do | |
495 | + get :create_production_cost, :profile => @enterprise.identifier | |
496 | + | |
497 | + resp = ActiveSupport::JSON.decode(@response.body) | |
498 | + assert_nil resp['name'] | |
499 | + assert_nil resp['id'] | |
500 | + assert !resp['ok'] | |
501 | + assert_match /blank/, resp['error_msg'] | |
502 | + end | |
503 | + | |
504 | + should 'display error if name of production cost is too long' do | |
505 | + get :create_production_cost, :profile => @enterprise.identifier, :id => 'a'*60 | |
506 | + | |
507 | + resp = ActiveSupport::JSON.decode(@response.body) | |
508 | + assert_nil resp['name'] | |
509 | + assert_nil resp['id'] | |
510 | + assert !resp['ok'] | |
511 | + assert_match /too long/, resp['error_msg'] | |
512 | + end | |
513 | + | |
471 | 514 | end | ... | ... |
test/unit/application_helper_test.rb
... | ... | @@ -625,13 +625,18 @@ class ApplicationHelperTest < ActiveSupport::TestCase |
625 | 625 | env = Environment.default |
626 | 626 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(false) |
627 | 627 | stubs(:environment).returns(env) |
628 | - assert_nil add_zoom_to_images | |
628 | + assert_nil add_zoom_to_article_images | |
629 | 629 | end |
630 | 630 | |
631 | 631 | should 'return code when :show_zoom_button_on_article_images is enabled in environment' do |
632 | 632 | env = Environment.default |
633 | 633 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(true) |
634 | 634 | stubs(:environment).returns(env) |
635 | + assert_not_nil add_zoom_to_article_images | |
636 | + end | |
637 | + | |
638 | + should 'return code when add_zoom_to_images' do | |
639 | + env = Environment.default | |
635 | 640 | assert_not_nil add_zoom_to_images |
636 | 641 | end |
637 | 642 | ... | ... |
test/unit/enterprise_homepage_test.rb
... | ... | @@ -16,43 +16,9 @@ class EnterpriseHomepageTest < ActiveSupport::TestCase |
16 | 16 | assert_kind_of String, EnterpriseHomepage.description |
17 | 17 | end |
18 | 18 | |
19 | - should 'display profile info' do | |
20 | - e = Enterprise.create!(:name => 'my test enterprise', :identifier => 'mytestenterprise', :contact_email => 'ent@noosfero.foo.bar', :contact_phone => '5555 5555') | |
21 | - a = EnterpriseHomepage.new(:name => 'article homepage') | |
22 | - e.articles << a | |
23 | - result = a.to_html | |
24 | - assert_match /ent@noosfero.foo.bar/, result | |
25 | - assert_match /5555 5555/, result | |
26 | - end | |
27 | - | |
28 | - should 'display products list' do | |
29 | - ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'Test enteprise') | |
30 | - prod = ent.products.create!(:name => 'Product test', :product_category => @product_category) | |
31 | - a = EnterpriseHomepage.new(:name => 'article homepage') | |
32 | - ent.articles << a | |
33 | - result = a.to_html | |
34 | - assert_match /Product test/, result | |
35 | - end | |
36 | - | |
37 | - should 'not display products list if environment do not let' do | |
38 | - e = Environment.default | |
39 | - e.enable('disable_products_for_enterprises') | |
40 | - e.save! | |
41 | - ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'Test enteprise', :environment_id => e.id) | |
42 | - prod = ent.products.create!(:name => 'Product test', :product_category => @product_category) | |
43 | - a = EnterpriseHomepage.new(:name => 'article homepage') | |
44 | - ent.articles << a | |
45 | - result = a.to_html | |
46 | - assert_no_match /Product test/, result | |
47 | - end | |
48 | - | |
49 | - should 'display link to product' do | |
50 | - ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'Test enteprise') | |
51 | - prod = ent.products.create!(:name => 'Product test', :product_category => @product_category) | |
52 | - a = EnterpriseHomepage.new(:name => 'article homepage') | |
53 | - ent.articles << a | |
54 | - result = a.to_html | |
55 | - assert_match /\/test_enterprise\/manage_products\/show\/#{prod.id}/, result | |
19 | + should 'return a valid body' do | |
20 | + e = EnterpriseHomepage.new(:name => 'sample enterprise homepage') | |
21 | + assert_not_nil e.to_html | |
56 | 22 | end |
57 | 23 | |
58 | 24 | should 'can display hits' do | ... | ... |
test/unit/enterprise_test.rb
... | ... | @@ -446,4 +446,8 @@ class EnterpriseTest < ActiveSupport::TestCase |
446 | 446 | assert_equal false, enterprise.receives_scrap_notification? |
447 | 447 | end |
448 | 448 | |
449 | + should 'have production cost' do | |
450 | + e = fast_create(Enterprise) | |
451 | + assert_respond_to e, :production_costs | |
452 | + end | |
449 | 453 | end | ... | ... |
test/unit/environment_test.rb
... | ... | @@ -1200,4 +1200,7 @@ class EnvironmentTest < ActiveSupport::TestCase |
1200 | 1200 | assert_not_includes environment.enabled_plugins, plugin |
1201 | 1201 | end |
1202 | 1202 | |
1203 | + should 'have production costs' do | |
1204 | + assert_respond_to Environment.default, :production_costs | |
1205 | + end | |
1203 | 1206 | end | ... | ... |
test/unit/highlights_block_test.rb
... | ... | @@ -77,6 +77,7 @@ class HighlightsBlockTest < ActiveSupport::TestCase |
77 | 77 | file = mock() |
78 | 78 | UploadedFile.expects(:find).with(1).returns(file) |
79 | 79 | file.expects(:public_filename).returns('address') |
80 | + UploadedFile.expects(:find).with(0).returns(nil) | |
80 | 81 | block = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => 'some', :position => '2', :title => 'Some'}]) |
81 | 82 | block.save! |
82 | 83 | block.reload |
... | ... | @@ -115,6 +116,12 @@ class HighlightsBlockTest < ActiveSupport::TestCase |
115 | 116 | f3 = mock() |
116 | 117 | f3.expects(:public_filename).returns('address') |
117 | 118 | UploadedFile.expects(:find).with(3).returns(f3) |
119 | + f4 = mock() | |
120 | + f4.expects(:public_filename).returns('address') | |
121 | + UploadedFile.expects(:find).with(4).returns(f4) | |
122 | + f5 = mock() | |
123 | + f5.expects(:public_filename).returns('address') | |
124 | + UploadedFile.expects(:find).with(5).returns(f5) | |
118 | 125 | block = HighlightsBlock.new |
119 | 126 | i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'} |
120 | 127 | i2 = {:image_id => 2, :address => '/address', :position => 1, :title => 'address'} | ... | ... |
test/unit/input_test.rb
... | ... | @@ -162,4 +162,19 @@ class InputTest < ActiveSupport::TestCase |
162 | 162 | assert_kind_of Unit, input.build_unit |
163 | 163 | end |
164 | 164 | |
165 | + should 'calculate cost of input' do | |
166 | + input = Input.new(:amount_used => 10, :price_per_unit => 2.00) | |
167 | + assert_equal 20.00, input.cost | |
168 | + end | |
169 | + | |
170 | + should 'cost 0 if amount not defined' do | |
171 | + input = Input.new(:price_per_unit => 2.00) | |
172 | + assert_equal 0.00, input.cost | |
173 | + end | |
174 | + | |
175 | + should 'cost 0 if price_per_unit is not defined' do | |
176 | + input = Input.new(:amount_used => 10) | |
177 | + assert_equal 0.00, input.cost | |
178 | + end | |
179 | + | |
165 | 180 | end | ... | ... |
... | ... | @@ -0,0 +1,81 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class PriceDetailTest < ActiveSupport::TestCase | |
4 | + | |
5 | + should 'have price 0 by default' do | |
6 | + p = PriceDetail.new | |
7 | + | |
8 | + assert p.price.zero? | |
9 | + end | |
10 | + | |
11 | + should 'return zero on price if it is blank' do | |
12 | + p = PriceDetail.new(:price => '') | |
13 | + | |
14 | + assert p.price.zero? | |
15 | + end | |
16 | + | |
17 | + should 'accept price in american\'s or brazilian\'s currency format' do | |
18 | + [ | |
19 | + [12.34, 12.34], | |
20 | + ["12.34", 12.34], | |
21 | + ["12,34", 12.34], | |
22 | + ["12.345.678,90", 12345678.90], | |
23 | + ["12,345,678.90", 12345678.90], | |
24 | + ["12.345.678", 12345678.00], | |
25 | + ["12,345,678", 12345678.00] | |
26 | + ].each do |input, output| | |
27 | + new_price_detail = PriceDetail.new(:price => input) | |
28 | + assert_equal output, new_price_detail.price | |
29 | + end | |
30 | + end | |
31 | + | |
32 | + should 'belongs to a product' do | |
33 | + p = PriceDetail.new | |
34 | + | |
35 | + assert_respond_to p, :product | |
36 | + end | |
37 | + | |
38 | + should 'product be mandatory' do | |
39 | + p = PriceDetail.new | |
40 | + p.valid? | |
41 | + | |
42 | + assert p.errors.invalid?(:product_id) | |
43 | + end | |
44 | + | |
45 | + should 'have production cost' do | |
46 | + product = fast_create(Product) | |
47 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
48 | + detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
49 | + | |
50 | + assert_equal cost, PriceDetail.find(detail.id).production_cost | |
51 | + end | |
52 | + | |
53 | + should 'production cost be mandatory' do | |
54 | + p = PriceDetail.new | |
55 | + p.valid? | |
56 | + | |
57 | + assert p.errors.invalid?(:production_cost_id) | |
58 | + end | |
59 | + | |
60 | + should 'th production cost be unique on scope of product' do | |
61 | + product = fast_create(Product) | |
62 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'environment') | |
63 | + | |
64 | + detail1 = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
65 | + detail2 = product.price_details.build(:production_cost_id => cost.id, :price => 10) | |
66 | + | |
67 | + detail2.valid? | |
68 | + assert detail2.errors.invalid?(:production_cost_id) | |
69 | + end | |
70 | + | |
71 | + should 'format values to float with 2 decimals' do | |
72 | + enterprise = fast_create(Enterprise) | |
73 | + product = fast_create(Product, :enterprise_id => enterprise.id) | |
74 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'environment') | |
75 | + | |
76 | + price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
77 | + | |
78 | + assert_equal "10.00", price_detail.formatted_value(:price) | |
79 | + end | |
80 | + | |
81 | +end | ... | ... |
test/unit/product_test.rb
... | ... | @@ -382,4 +382,132 @@ class ProductTest < ActiveSupport::TestCase |
382 | 382 | assert_includes Product.find_by_contents('thing'), p2 |
383 | 383 | end |
384 | 384 | |
385 | + should 'respond to price details' do | |
386 | + product = Product.new | |
387 | + assert_respond_to product, :price_details | |
388 | + end | |
389 | + | |
390 | + should 'return total value of inputs' do | |
391 | + product = fast_create(Product) | |
392 | + first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) | |
393 | + second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) | |
394 | + | |
395 | + assert_equal 50.0, product.inputs_cost | |
396 | + end | |
397 | + | |
398 | + should 'return 0 on total value of inputs if has no input' do | |
399 | + product = fast_create(Product) | |
400 | + | |
401 | + assert product.inputs_cost.zero? | |
402 | + end | |
403 | + | |
404 | + should 'know if price is described' do | |
405 | + product = fast_create(Product, :price => 30.0) | |
406 | + | |
407 | + first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 1) | |
408 | + assert !Product.find(product.id).price_described? | |
409 | + | |
410 | + second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) | |
411 | + assert Product.find(product.id).price_described? | |
412 | + end | |
413 | + | |
414 | + should 'return false on price_described if price of product is not defined' do | |
415 | + product = fast_create(Product) | |
416 | + | |
417 | + assert_equal false, product.price_described? | |
418 | + end | |
419 | + | |
420 | + should 'create price details' do | |
421 | + product = fast_create(Product) | |
422 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
423 | + assert product.price_details.empty? | |
424 | + | |
425 | + product.update_price_details([{:production_cost_id => cost.id, :price => 10}]) | |
426 | + assert_equal 1, Product.find(product.id).price_details.size | |
427 | + end | |
428 | + | |
429 | + should 'update price of a cost on price details' do | |
430 | + product = fast_create(Product) | |
431 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
432 | + cost2 = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
433 | + price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
434 | + assert !product.price_details.empty? | |
435 | + | |
436 | + product.update_price_details([{:production_cost_id => cost.id, :price => 20}, {:production_cost_id => cost2.id, :price => 30}]) | |
437 | + assert_equal 20, product.price_details.find_by_production_cost_id(cost.id).price | |
438 | + assert_equal 2, Product.find(product.id).price_details.size | |
439 | + end | |
440 | + | |
441 | + should 'destroy price details if product is removed' do | |
442 | + product = fast_create(Product) | |
443 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
444 | + price_detail = product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
445 | + | |
446 | + assert_difference PriceDetail, :count, -1 do | |
447 | + product.destroy | |
448 | + end | |
449 | + end | |
450 | + | |
451 | + should 'have production costs' do | |
452 | + product = fast_create(Product) | |
453 | + cost = fast_create(ProductionCost, :owner_id => Environment.default.id, :owner_type => 'Environment') | |
454 | + product.price_details.create(:production_cost_id => cost.id, :price => 10) | |
455 | + assert_equal [cost], Product.find(product.id).production_costs | |
456 | + end | |
457 | + | |
458 | + should 'return production costs from enterprise and environment' do | |
459 | + ent = fast_create(Enterprise) | |
460 | + product = fast_create(Product, :enterprise_id => ent.id) | |
461 | + ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') | |
462 | + env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') | |
463 | + | |
464 | + assert_equal [env_production_cost, ent_production_cost], product.available_production_costs | |
465 | + end | |
466 | + | |
467 | + should 'return all production costs' do | |
468 | + ent = fast_create(Enterprise) | |
469 | + product = fast_create(Product, :enterprise_id => ent.id) | |
470 | + | |
471 | + env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') | |
472 | + ent_production_cost = fast_create(ProductionCost, :owner_id => ent.id, :owner_type => 'Profile') | |
473 | + product.price_details.create(:production_cost => env_production_cost, :product => product) | |
474 | + assert_equal [env_production_cost, ent_production_cost], product.available_production_costs | |
475 | + end | |
476 | + | |
477 | + should 'return total value of production costs' do | |
478 | + ent = fast_create(Enterprise) | |
479 | + product = fast_create(Product, :enterprise_id => ent.id) | |
480 | + | |
481 | + env_production_cost = fast_create(ProductionCost, :owner_id => ent.environment.id, :owner_type => 'Environment') | |
482 | + price_detail = product.price_details.create(:production_cost => env_production_cost, :price => 10) | |
483 | + | |
484 | + input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) | |
485 | + | |
486 | + assert_equal price_detail.price + input.cost, product.total_production_cost | |
487 | + end | |
488 | + | |
489 | + should 'return inputs cost as total value of production costs if has no price details' do | |
490 | + ent = fast_create(Enterprise) | |
491 | + product = fast_create(Product, :enterprise_id => ent.id) | |
492 | + | |
493 | + input = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) | |
494 | + | |
495 | + assert_equal input.cost, product.total_production_cost | |
496 | + end | |
497 | + | |
498 | + should 'return 0 on total production cost if has no input and price details' do | |
499 | + product = fast_create(Product) | |
500 | + | |
501 | + assert product.total_production_cost.zero? | |
502 | + end | |
503 | + | |
504 | + should 'format inputs cost values to float with 2 decimals' do | |
505 | + ent = fast_create(Enterprise) | |
506 | + product = fast_create(Product, :enterprise_id => ent.id) | |
507 | + first = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2) | |
508 | + second = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1) | |
509 | + | |
510 | + assert_equal "50.00", product.formatted_value(:inputs_cost) | |
511 | + end | |
512 | + | |
385 | 513 | end | ... | ... |
... | ... | @@ -0,0 +1,102 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class ProductionCostTest < ActiveSupport::TestCase | |
4 | + | |
5 | + should 'have name' do | |
6 | + p = ProductionCost.new | |
7 | + p.valid? | |
8 | + assert p.errors.invalid?(:name) | |
9 | + | |
10 | + p.name = 'Taxes' | |
11 | + p.valid? | |
12 | + assert !p.errors.invalid?(:name) | |
13 | + end | |
14 | + | |
15 | + should 'not validates name if it is blank' do | |
16 | + p = ProductionCost.new | |
17 | + | |
18 | + p.valid? | |
19 | + assert_equal 1, p.errors['name'].to_a.count | |
20 | + end | |
21 | + | |
22 | + should 'not have a too long name' do | |
23 | + p = ProductionCost.new | |
24 | + | |
25 | + p.name = 'a'*40 | |
26 | + p.valid? | |
27 | + assert p.errors.invalid?(:name) | |
28 | + | |
29 | + p.name = 'a'*30 | |
30 | + p.valid? | |
31 | + assert !p.errors.invalid?(:name) | |
32 | + end | |
33 | + | |
34 | + should 'not have duplicated name on same environment' do | |
35 | + cost = ProductionCost.create(:name => 'Taxes', :owner => Environment.default) | |
36 | + | |
37 | + invalid_cost = ProductionCost.new(:name => 'Taxes', :owner => Environment.default) | |
38 | + invalid_cost.valid? | |
39 | + | |
40 | + assert invalid_cost.errors.invalid?(:name) | |
41 | + end | |
42 | + | |
43 | + should 'not have duplicated name on same enterprise' do | |
44 | + enterprise = fast_create(Enterprise) | |
45 | + cost = ProductionCost.create(:name => 'Taxes', :owner => enterprise) | |
46 | + | |
47 | + invalid_cost = ProductionCost.new(:name => 'Taxes', :owner => enterprise) | |
48 | + invalid_cost.valid? | |
49 | + | |
50 | + assert invalid_cost.errors.invalid?(:name) | |
51 | + end | |
52 | + | |
53 | + should 'not allow same name on enterprise if already has on environment' do | |
54 | + enterprise = fast_create(Enterprise) | |
55 | + | |
56 | + cost1 = ProductionCost.create(:name => 'Taxes', :owner => Environment.default) | |
57 | + cost2 = ProductionCost.new(:name => 'Taxes', :owner => enterprise) | |
58 | + | |
59 | + cost2.valid? | |
60 | + | |
61 | + assert !cost2.errors.invalid?(:name) | |
62 | + end | |
63 | + | |
64 | + should 'allow duplicated name on different enterprises' do | |
65 | + enterprise = fast_create(Enterprise) | |
66 | + enterprise2 = fast_create(Enterprise) | |
67 | + | |
68 | + cost1 = ProductionCost.create(:name => 'Taxes', :owner => enterprise) | |
69 | + cost2 = ProductionCost.new(:name => 'Taxes', :owner => enterprise2) | |
70 | + | |
71 | + cost2.valid? | |
72 | + | |
73 | + assert !cost2.errors.invalid?(:name) | |
74 | + end | |
75 | + | |
76 | + should 'be associated to an environment as owner' do | |
77 | + p = ProductionCost.new | |
78 | + p.valid? | |
79 | + assert p.errors.invalid?(:owner) | |
80 | + | |
81 | + p.owner = Environment.default | |
82 | + p.valid? | |
83 | + assert !p.errors.invalid?(:owner) | |
84 | + end | |
85 | + | |
86 | + should 'be associated to an enterprise as owner' do | |
87 | + enterprise = fast_create(Enterprise) | |
88 | + p = ProductionCost.new | |
89 | + p.valid? | |
90 | + assert p.errors.invalid?(:owner) | |
91 | + | |
92 | + p.owner = enterprise | |
93 | + p.valid? | |
94 | + assert !p.errors.invalid?(:owner) | |
95 | + end | |
96 | + | |
97 | + should 'create a production cost on an enterprise' do | |
98 | + enterprise = fast_create(Enterprise) | |
99 | + enterprise.production_costs.create(:name => 'Energy') | |
100 | + assert_equal ['Energy'], enterprise.production_costs.map(&:name) | |
101 | + end | |
102 | +end | ... | ... |