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,6 +111,36 @@ class ManageProductsController < ApplicationController | ||
111 | end | 111 | end |
112 | end | 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 | def destroy | 144 | def destroy |
115 | @product = @profile.products.find(params[:id]) | 145 | @product = @profile.products.find(params[:id]) |
116 | if @product.destroy | 146 | if @product.destroy |
@@ -167,4 +197,18 @@ class ManageProductsController < ApplicationController | @@ -167,4 +197,18 @@ class ManageProductsController < ApplicationController | ||
167 | end | 197 | end |
168 | end | 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 | end | 214 | end |
app/controllers/public/catalog_controller.rb
@@ -4,10 +4,11 @@ class CatalogController < PublicController | @@ -4,10 +4,11 @@ class CatalogController < PublicController | ||
4 | before_filter :check_enterprise_and_environment | 4 | before_filter :check_enterprise_and_environment |
5 | 5 | ||
6 | def index | 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 | end | 8 | end |
9 | 9 | ||
10 | protected | 10 | protected |
11 | + | ||
11 | def check_enterprise_and_environment | 12 | def check_enterprise_and_environment |
12 | unless @profile.kind_of?(Enterprise) && !@profile.environment.enabled?('disable_products_for_enterprises') | 13 | unless @profile.kind_of?(Enterprise) && !@profile.environment.enabled?('disable_products_for_enterprises') |
13 | redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' | 14 | redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' |
app/helpers/application_helper.rb
@@ -1254,25 +1254,27 @@ module ApplicationHelper | @@ -1254,25 +1254,27 @@ module ApplicationHelper | ||
1254 | task.information[:message] % values | 1254 | task.information[:message] % values |
1255 | end | 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 | def add_zoom_to_images | 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 | end | 1278 | end |
1277 | 1279 | ||
1278 | def render_dialog_error_messages(instance_name) | 1280 | def render_dialog_error_messages(instance_name) |
app/helpers/catalog_helper.rb
1 | module CatalogHelper | 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 | end | 6 | end |
app/helpers/display_helper.rb
@@ -8,6 +8,20 @@ module DisplayHelper | @@ -8,6 +8,20 @@ module DisplayHelper | ||
8 | opts | 8 | opts |
9 | end | 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 | def product_path(product) | 25 | def product_path(product) |
12 | product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url | 26 | product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url |
13 | end | 27 | end |
app/helpers/manage_products_helper.rb
@@ -271,4 +271,23 @@ module ManageProductsHelper | @@ -271,4 +271,23 @@ module ManageProductsHelper | ||
271 | return input_amount_used if input.unit.blank? | 271 | return input_amount_used if input.unit.blank? |
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') } | 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 | end | 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 | end | 293 | end |
app/models/enterprise.rb
@@ -6,6 +6,7 @@ class Enterprise < Organization | @@ -6,6 +6,7 @@ class Enterprise < Organization | ||
6 | 6 | ||
7 | has_many :products, :dependent => :destroy, :order => 'name ASC' | 7 | has_many :products, :dependent => :destroy, :order => 'name ASC' |
8 | has_many :inputs, :through => :products | 8 | has_many :inputs, :through => :products |
9 | + has_many :production_costs, :as => :owner | ||
9 | 10 | ||
10 | has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people' | 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,18 +12,13 @@ class EnterpriseHomepage < Article | ||
12 | profile.nil? ? _('Homepage') : profile.name | 12 | profile.nil? ? _('Homepage') : profile.name |
13 | end | 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 | end | 22 | end |
28 | 23 | ||
29 | def can_display_hits? | 24 | def can_display_hits? |
app/models/environment.rb
@@ -174,6 +174,7 @@ class Environment < ActiveRecord::Base | @@ -174,6 +174,7 @@ class Environment < ActiveRecord::Base | ||
174 | acts_as_accessible | 174 | acts_as_accessible |
175 | 175 | ||
176 | has_many :units, :order => 'position' | 176 | has_many :units, :order => 'position' |
177 | + has_many :production_costs, :as => :owner | ||
177 | 178 | ||
178 | def superior_intances | 179 | def superior_intances |
179 | [self, nil] | 180 | [self, nil] |
app/models/image.rb
@@ -9,15 +9,15 @@ class Image < ActiveRecord::Base | @@ -9,15 +9,15 @@ class Image < ActiveRecord::Base | ||
9 | has_attachment :content_type => :image, | 9 | has_attachment :content_type => :image, |
10 | :storage => :file_system, | 10 | :storage => :file_system, |
11 | :path_prefix => 'public/image_uploads', | 11 | :path_prefix => 'public/image_uploads', |
12 | - :resize_to => '320x200>', | 12 | + :resize_to => '800x600>', |
13 | :thumbnails => { :big => '150x150', | 13 | :thumbnails => { :big => '150x150', |
14 | :thumb => '100x100', | 14 | :thumb => '100x100', |
15 | :portrait => '64x64', | 15 | :portrait => '64x64', |
16 | :minor => '50x50', | 16 | :minor => '50x50', |
17 | :icon => '20x20!' }, | 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 | delay_attachment_fu_thumbnails | 22 | delay_attachment_fu_thumbnails |
23 | 23 |
app/models/input.rb
@@ -45,6 +45,18 @@ class Input < ActiveRecord::Base | @@ -45,6 +45,18 @@ class Input < ActiveRecord::Base | ||
45 | %w[price_per_unit amount_used].each do |field| | 45 | %w[price_per_unit amount_used].each do |field| |
46 | return true unless self.send(field).blank? | 46 | return true unless self.send(field).blank? |
47 | end | 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 | end | 61 | end |
50 | end | 62 | end |
@@ -0,0 +1,27 @@ | @@ -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,6 +5,8 @@ class Product < ActiveRecord::Base | ||
5 | has_many :product_qualifiers | 5 | has_many :product_qualifiers |
6 | has_many :qualifiers, :through => :product_qualifiers | 6 | has_many :qualifiers, :through => :product_qualifiers |
7 | has_many :inputs, :dependent => :destroy, :order => 'position' | 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 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true | 11 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true |
10 | validates_presence_of :product_category_id | 12 | validates_presence_of :product_category_id |
@@ -101,12 +103,13 @@ class Product < ActiveRecord::Base | @@ -101,12 +103,13 @@ class Product < ActiveRecord::Base | ||
101 | enterprise.public_profile | 103 | enterprise.public_profile |
102 | end | 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 | end | 109 | end |
107 | 110 | ||
108 | def price_with_discount | 111 | def price_with_discount |
109 | - price - discount if discount | 112 | + discount ? (price - discount) : price |
110 | end | 113 | end |
111 | 114 | ||
112 | def price=(value) | 115 | def price=(value) |
@@ -125,6 +128,23 @@ class Product < ActiveRecord::Base | @@ -125,6 +128,23 @@ class Product < ActiveRecord::Base | ||
125 | end | 128 | end |
126 | end | 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 | def has_basic_info? | 148 | def has_basic_info? |
129 | %w[unit price discount].each do |field| | 149 | %w[unit price discount].each do |field| |
130 | return true if !self.send(field).blank? | 150 | return true if !self.send(field).blank? |
@@ -153,4 +173,43 @@ class Product < ActiveRecord::Base | @@ -153,4 +173,43 @@ class Product < ActiveRecord::Base | ||
153 | true | 173 | true |
154 | end | 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 | end | 215 | end |
@@ -0,0 +1,8 @@ | @@ -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 | <% language = FastGettext.locale %> | 2 | <% language = FastGettext.locale %> |
3 | <%= javascript_include_tag 'jquery-validation/localization/messages_'+language, 'jquery-validation/localization/methods_'+language %> | 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,13 +11,13 @@ | ||
11 | <%= stylesheet_link_tag noosfero_stylesheets, :cache => 'cache' %> | 11 | <%= stylesheet_link_tag noosfero_stylesheets, :cache => 'cache' %> |
12 | <%= stylesheet_link_tag template_stylesheet_path %> | 12 | <%= stylesheet_link_tag template_stylesheet_path %> |
13 | <%= stylesheet_link_tag icon_theme_stylesheet_path %> | 13 | <%= stylesheet_link_tag icon_theme_stylesheet_path %> |
14 | - <%= stylesheet_link_tag theme_stylesheet_path %> | ||
15 | <%= stylesheet_link_tag jquery_ui_theme_stylesheet_path %> | 14 | <%= stylesheet_link_tag jquery_ui_theme_stylesheet_path %> |
16 | <% @plugins.enabled_plugins.each do |plugin| %> | 15 | <% @plugins.enabled_plugins.each do |plugin| %> |
17 | <% if plugin.stylesheet? %> | 16 | <% if plugin.stylesheet? %> |
18 | <%= stylesheet_tag plugin.class.public_path('style.css'), {} %> | 17 | <%= stylesheet_tag plugin.class.public_path('style.css'), {} %> |
19 | <% end %> | 18 | <% end %> |
20 | <% end %> | 19 | <% end %> |
20 | + <%= stylesheet_link_tag theme_stylesheet_path %> | ||
21 | 21 | ||
22 | <%# Add custom tags/styles/etc via content_for %> | 22 | <%# Add custom tags/styles/etc via content_for %> |
23 | <%= yield :head %> | 23 | <%= yield :head %> |
@@ -30,7 +30,7 @@ | @@ -30,7 +30,7 @@ | ||
30 | <%= | 30 | <%= |
31 | @plugins.map(:head_ending).collect do |content| | 31 | @plugins.map(:head_ending).collect do |content| |
32 | content.respond_to?(:call) ? content.call : content | 32 | content.respond_to?(:call) ? content.call : content |
33 | - end.join('\n') | 33 | + end.join("\n") |
34 | %> | 34 | %> |
35 | </head> | 35 | </head> |
36 | <body class="<%= | 36 | <body class="<%= |
@@ -45,7 +45,7 @@ | @@ -45,7 +45,7 @@ | ||
45 | <%= | 45 | <%= |
46 | @plugins.map(:body_beginning).collect do |content| | 46 | @plugins.map(:body_beginning).collect do |content| |
47 | content.respond_to?(:call) ? content.call : content | 47 | content.respond_to?(:call) ? content.call : content |
48 | - end.join('\n') | 48 | + end.join("\n") |
49 | %> | 49 | %> |
50 | 50 | ||
51 | <div id="wrap-1"> | 51 | <div id="wrap-1"> |
app/views/layouts/application.rhtml
@@ -27,11 +27,8 @@ | @@ -27,11 +27,8 @@ | ||
27 | <%# Add custom tags/styles/etc via content_for %> | 27 | <%# Add custom tags/styles/etc via content_for %> |
28 | <%= yield :head %> | 28 | <%= yield :head %> |
29 | <%= javascript_tag('render_all_jquery_ui_widgets()') %> | 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 | </head> | 32 | </head> |
36 | 33 | ||
37 | <body class='noosfero category<%= category_color %><%= | 34 | <body class='noosfero category<%= category_color %><%= |
@@ -0,0 +1,18 @@ | @@ -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,15 +49,12 @@ | ||
49 | <%= hidden_field_tag "product[qualifiers_list]" %> | 49 | <%= hidden_field_tag "product[qualifiers_list]" %> |
50 | <% end %> | 50 | <% end %> |
51 | 51 | ||
52 | + <%= hidden_field_tag 'info-bar-update-url', @product.price_composition_bar_display_url, :class => 'bar-update-url' %> | ||
53 | + | ||
52 | <% button_bar do %> | 54 | <% button_bar do %> |
53 | <%= submit_button :save, _('Save') %> | 55 | <%= submit_button :save, _('Save') %> |
54 | <%= cancel_edit_product_link(@product, 'info') %> | 56 | <%= cancel_edit_product_link(@product, 'info') %> |
55 | <% end %> | 57 | <% end %> |
56 | <% end %> | 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 | <% form_for(@input, :url => {:controller => 'manage_products', :action => 'edit_input', :id => @input}, | 1 | <% form_for(@input, :url => {:controller => 'manage_products', :action => 'edit_input', :id => @input}, |
2 | :html => {:method => 'post', :id => "edit-input-#{ @input.id }-form"}) do |f| %> | 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 | <table> | 7 | <table> |
4 | <tr> | 8 | <tr> |
5 | <td><%= f.label :amount_used, label_amount_used(@input), :class => 'formlabel' %></td> | 9 | <td><%= f.label :amount_used, label_amount_used(@input), :class => 'formlabel' %></td> |
@@ -0,0 +1,14 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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,7 +23,7 @@ | ||
23 | 23 | ||
24 | <br style='clear: both'/> | 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 | <div class='ui-tabs' id='product-<%= @product.id %>-tabs'> | 27 | <div class='ui-tabs' id='product-<%= @product.id %>-tabs'> |
28 | <ul> | 28 | <ul> |
29 | <% if !@product.description.blank? || @allowed_user %> | 29 | <% if !@product.description.blank? || @allowed_user %> |
@@ -32,6 +32,9 @@ | @@ -32,6 +32,9 @@ | ||
32 | <% if !@product.inputs.empty? || @allowed_user %> | 32 | <% if !@product.inputs.empty? || @allowed_user %> |
33 | <li class='tab'><a href='#product-inputs'><%= _('Inputs and raw material') %></a></li> | 33 | <li class='tab'><a href='#product-inputs'><%= _('Inputs and raw material') %></a></li> |
34 | <% end %> | 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 | </ul> | 38 | </ul> |
36 | <div id='product-description'> | 39 | <div id='product-description'> |
37 | <%= render :partial => 'manage_products/display_description' %> | 40 | <%= render :partial => 'manage_products/display_description' %> |
@@ -39,6 +42,12 @@ | @@ -39,6 +42,12 @@ | ||
39 | <div id='product-inputs'> | 42 | <div id='product-inputs'> |
40 | <%= render :partial => 'manage_products/display_inputs' %> | 43 | <%= render :partial => 'manage_products/display_inputs' %> |
41 | </div> | 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 | </div> | 51 | </div> |
43 | <% end %> | 52 | <% end %> |
44 | 53 |
@@ -0,0 +1,10 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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,6 +323,14 @@ ActiveRecord::Schema.define(:version => 20111004184104) do | ||
323 | t.datetime "updated_at" | 323 | t.datetime "updated_at" |
324 | end | 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 | create_table "product_categorizations", :force => true do |t| | 334 | create_table "product_categorizations", :force => true do |t| |
327 | t.integer "category_id" | 335 | t.integer "category_id" |
328 | t.integer "product_id" | 336 | t.integer "product_id" |
@@ -342,6 +350,14 @@ ActiveRecord::Schema.define(:version => 20111004184104) do | @@ -342,6 +350,14 @@ ActiveRecord::Schema.define(:version => 20111004184104) do | ||
342 | t.datetime "updated_at" | 350 | t.datetime "updated_at" |
343 | end | 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 | create_table "products", :force => true do |t| | 361 | create_table "products", :force => true do |t| |
346 | t.integer "enterprise_id" | 362 | t.integer "enterprise_id" |
347 | t.integer "product_category_id" | 363 | t.integer "product_category_id" |
features/admin_categories.feature
@@ -43,7 +43,7 @@ Feature: manage categories | @@ -43,7 +43,7 @@ Feature: manage categories | ||
43 | When I follow "Show" | 43 | When I follow "Show" |
44 | Then I should see "Vegetarian" | 44 | Then I should see "Vegetarian" |
45 | And I should see "Steak" | 45 | And I should see "Steak" |
46 | - When I follow "Hide" | 46 | + When I follow "Hide" and sleep 1 second |
47 | Then I should not see "Vegetarian" | 47 | Then I should not see "Vegetarian" |
48 | And I should not see "Steak" | 48 | And I should not see "Steak" |
49 | 49 |
@@ -0,0 +1,309 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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,19 +35,20 @@ Feature: manage products | ||
35 | | redemoinho | bicycle | Bike J | bicycle 10 | | 35 | | redemoinho | bicycle | Bike J | bicycle 10 | |
36 | | redemoinho | bicycle | Bike K | bicycle 11 | | 36 | | redemoinho | bicycle | Bike K | bicycle 11 | |
37 | When I go to /catalog/redemoinho | 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 | When I follow "Next" | 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 | Scenario: listing products and services | 53 | Scenario: listing products and services |
53 | Given I am logged in as "joaosilva" | 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,8 +150,16 @@ Given /^the following products?$/ do |table| | ||
150 | data = item.dup | 150 | data = item.dup |
151 | owner = Enterprise[data.delete("owner")] | 151 | owner = Enterprise[data.delete("owner")] |
152 | category = Category.find_by_slug(data.delete("category").to_slug) | 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 | end | 163 | end |
156 | end | 164 | end |
157 | 165 | ||
@@ -214,6 +222,22 @@ Given /^the following certifiers$/ do |table| | @@ -214,6 +222,22 @@ Given /^the following certifiers$/ do |table| | ||
214 | end | 222 | end |
215 | end | 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 | Given /^I am logged in as "(.+)"$/ do |username| | 241 | Given /^I am logged in as "(.+)"$/ do |username| |
218 | visit('/account/logout') | 242 | visit('/account/logout') |
219 | visit('/account/login') | 243 | visit('/account/login') |
@@ -493,3 +517,32 @@ end | @@ -493,3 +517,32 @@ end | ||
493 | When 'I log off' do | 517 | When 'I log off' do |
494 | visit '/account/logout' | 518 | visit '/account/logout' |
495 | end | 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,3 +117,17 @@ Then /^the select for category "([^\"]*)" should be visible$/ do |name| | ||
117 | category = Category.find_by_name(name) | 117 | category = Category.find_by_name(name) |
118 | selenium.is_visible(string_to_element_locator("option=#{category.id}")).should be_true | 118 | selenium.is_visible(string_to_element_locator("option=#{category.id}")).should be_true |
119 | end | 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
@@ -19,6 +19,7 @@ end | @@ -19,6 +19,7 @@ end | ||
19 | When /^I visit "([^\"]*)" and wait$/ do |page_name| | 19 | When /^I visit "([^\"]*)" and wait$/ do |page_name| |
20 | visit path_to(page_name) | 20 | visit path_to(page_name) |
21 | selenium.wait_for_page_to_load(10000) | 21 | selenium.wait_for_page_to_load(10000) |
22 | +# selenium.wait_for_page | ||
22 | end | 23 | end |
23 | 24 | ||
24 | When /^I press "([^\"]*)"$/ do |button| | 25 | When /^I press "([^\"]*)"$/ do |button| |
plugins/shopping_cart/controllers/shopping_cart_plugin_profile_controller.rb
@@ -118,7 +118,7 @@ class ShoppingCartPluginProfileController < ProfileController | @@ -118,7 +118,7 @@ class ShoppingCartPluginProfileController < ProfileController | ||
118 | session[:cart][:visibility] = true | 118 | session[:cart][:visibility] = true |
119 | render :text => { | 119 | render :text => { |
120 | :ok => true, | 120 | :ok => true, |
121 | - :message => _('Cart displayed.'), | 121 | + :message => _('Basket displayed.'), |
122 | :error => {:code => 0} | 122 | :error => {:code => 0} |
123 | }.to_json | 123 | }.to_json |
124 | rescue Exception => exception | 124 | rescue Exception => exception |
@@ -137,7 +137,7 @@ class ShoppingCartPluginProfileController < ProfileController | @@ -137,7 +137,7 @@ class ShoppingCartPluginProfileController < ProfileController | ||
137 | session[:cart][:visibility] = false | 137 | session[:cart][:visibility] = false |
138 | render :text => { | 138 | render :text => { |
139 | :ok => true, | 139 | :ok => true, |
140 | - :message => _('Cart Hidden.'), | 140 | + :message => _('Basket hidden.'), |
141 | :error => {:code => 0} | 141 | :error => {:code => 0} |
142 | }.to_json | 142 | }.to_json |
143 | rescue Exception => exception | 143 | rescue Exception => exception |
@@ -173,7 +173,7 @@ class ShoppingCartPluginProfileController < ProfileController | @@ -173,7 +173,7 @@ class ShoppingCartPluginProfileController < ProfileController | ||
173 | :ok => false, | 173 | :ok => false, |
174 | :error => { | 174 | :error => { |
175 | :code => 2, | 175 | :code => 2, |
176 | - :message => _("There is no cart.") | 176 | + :message => _("There is no basket.") |
177 | } | 177 | } |
178 | }.to_json | 178 | }.to_json |
179 | return false | 179 | return false |
@@ -203,7 +203,7 @@ class ShoppingCartPluginProfileController < ProfileController | @@ -203,7 +203,7 @@ class ShoppingCartPluginProfileController < ProfileController | ||
203 | :ok => false, | 203 | :ok => false, |
204 | :error => { | 204 | :error => { |
205 | :code => 4, | 205 | :code => 4, |
206 | - :message => _("The cart doesn't have this product.") | 206 | + :message => _("The basket doesn't have this product.") |
207 | } | 207 | } |
208 | }.to_json | 208 | }.to_json |
209 | return false | 209 | return false |
plugins/shopping_cart/lib/shopping_cart_plugin.rb
@@ -4,17 +4,17 @@ require_dependency 'shopping_cart_plugin/ext/person' | @@ -4,17 +4,17 @@ require_dependency 'shopping_cart_plugin/ext/person' | ||
4 | class ShoppingCartPlugin < Noosfero::Plugin | 4 | class ShoppingCartPlugin < Noosfero::Plugin |
5 | 5 | ||
6 | def self.plugin_name | 6 | def self.plugin_name |
7 | - "Shopping Cart" | 7 | + "Shopping Basket" |
8 | end | 8 | end |
9 | 9 | ||
10 | def self.plugin_description | 10 | def self.plugin_description |
11 | - _("A shopping cart feature for enterprises") | 11 | + _("A shopping basket feature for enterprises") |
12 | end | 12 | end |
13 | 13 | ||
14 | def add_to_cart_button(item, enterprise = context.profile) | 14 | def add_to_cart_button(item, enterprise = context.profile) |
15 | if enterprise.shopping_cart && item.available | 15 | if enterprise.shopping_cart && item.available |
16 | lambda { | 16 | lambda { |
17 | - link_to(_('Add to cart'), "add:#{item.name}", | 17 | + link_to(_('Add to basket'), "add:#{item.name}", |
18 | :class => 'cart-add-item', | 18 | :class => 'cart-add-item', |
19 | :onclick => "Cart.addItem('#{enterprise.identifier}', #{item.id}, this); return false" | 19 | :onclick => "Cart.addItem('#{enterprise.identifier}', #{item.id}, this); return false" |
20 | ) | 20 | ) |
@@ -41,10 +41,10 @@ class ShoppingCartPlugin < Noosfero::Plugin | @@ -41,10 +41,10 @@ class ShoppingCartPlugin < Noosfero::Plugin | ||
41 | def control_panel_buttons | 41 | def control_panel_buttons |
42 | buttons = [] | 42 | buttons = [] |
43 | if context.profile.enterprise? | 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 | end | 45 | end |
46 | if context.profile.enterprise? && context.profile.shopping_cart | 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 | end | 48 | end |
49 | 49 | ||
50 | buttons | 50 | buttons |
plugins/shopping_cart/public/cart.js
@@ -62,7 +62,7 @@ function Cart(config) { | @@ -62,7 +62,7 @@ function Cart(config) { | ||
62 | '<div class="item-price">' + | 62 | '<div class="item-price">' + |
63 | '<input size="1" value="'+item.quantity+'" />'+ (item.price ? '× '+ item.price : '') +'</div>' + | 63 | '<input size="1" value="'+item.quantity+'" />'+ (item.price ? '× '+ item.price : '') +'</div>' + |
64 | ' <a href="remove:'+item.name+'" onclick="Cart.removeItem(\''+this.enterprise+'\', '+item.id+'); return false"' + | 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 | ).appendTo(li); | 66 | ).appendTo(li); |
67 | var input = $("input", li)[0]; | 67 | var input = $("input", li)[0]; |
68 | input.lastValue = input.value; | 68 | input.lastValue = input.value; |
@@ -304,6 +304,10 @@ function Cart(config) { | @@ -304,6 +304,10 @@ function Cart(config) { | ||
304 | }); | 304 | }); |
305 | } | 305 | } |
306 | 306 | ||
307 | + Cart.colorbox_close = function() { | ||
308 | + $.colorbox.close(); | ||
309 | + } | ||
310 | + | ||
307 | $(function(){ | 311 | $(function(){ |
308 | $('.cart-add-item').button({ icons: { primary: 'ui-icon-cart'} }) | 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 @@ | @@ -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,7 +14,7 @@ | ||
14 | height="48" | 14 | height="48" |
15 | id="svg2" | 15 | id="svg2" |
16 | version="1.1" | 16 | version="1.1" |
17 | - inkscape:version="0.47 r22583" | 17 | + inkscape:version="0.48.2 r9819" |
18 | sodipodi:docname="purchase-report.svg" | 18 | sodipodi:docname="purchase-report.svg" |
19 | inkscape:export-filename="/home/aurium/purchase-report.png" | 19 | inkscape:export-filename="/home/aurium/purchase-report.png" |
20 | inkscape:export-xdpi="90" | 20 | inkscape:export-xdpi="90" |
@@ -352,10 +352,10 @@ | @@ -352,10 +352,10 @@ | ||
352 | inkscape:document-units="px" | 352 | inkscape:document-units="px" |
353 | inkscape:current-layer="layer1" | 353 | inkscape:current-layer="layer1" |
354 | showgrid="true" | 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 | inkscape:window-maximized="1"> | 359 | inkscape:window-maximized="1"> |
360 | <inkscape:grid | 360 | <inkscape:grid |
361 | type="xygrid" | 361 | type="xygrid" |
@@ -419,120 +419,17 @@ | @@ -419,120 +419,17 @@ | ||
419 | ry="0" /> | 419 | ry="0" /> |
420 | <g | 420 | <g |
421 | id="g4873" | 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 | <path | 424 | <path |
529 | sodipodi:nodetypes="cccccc" | 425 | sodipodi:nodetypes="cccccc" |
530 | d="m 29.5,1015.8622 11,0 m -11,-3 11,0 m -11,-3 11,0" | 426 | d="m 29.5,1015.8622 11,0 m -11,-3 11,0 m -11,-3 11,0" |
531 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" | 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 | <path | 430 | <path |
534 | transform="translate(0,1004.3622)" | 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 | sodipodi:ry="1" | 433 | sodipodi:ry="1" |
537 | sodipodi:rx="1" | 434 | sodipodi:rx="1" |
538 | sodipodi:cy="5.5" | 435 | sodipodi:cy="5.5" |
@@ -548,11 +445,11 @@ | @@ -548,11 +445,11 @@ | ||
548 | sodipodi:cy="5.5" | 445 | sodipodi:cy="5.5" |
549 | sodipodi:rx="1" | 446 | sodipodi:rx="1" |
550 | sodipodi:ry="1" | 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 | transform="translate(0,1007.3622)" /> | 449 | transform="translate(0,1007.3622)" /> |
553 | <path | 450 | <path |
554 | transform="translate(0,1010.3622)" | 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 | sodipodi:ry="1" | 453 | sodipodi:ry="1" |
557 | sodipodi:rx="1" | 454 | sodipodi:rx="1" |
558 | sodipodi:cy="5.5" | 455 | sodipodi:cy="5.5" |
@@ -564,7 +461,8 @@ | @@ -564,7 +461,8 @@ | ||
564 | id="path4811" | 461 | id="path4811" |
565 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" | 462 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" |
566 | d="m 29.5,1029.8622 11,0 m -11,-3 11,0 m -11,-3 11,0" | 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 | <path | 466 | <path |
569 | sodipodi:type="arc" | 467 | sodipodi:type="arc" |
570 | 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" | 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,11 +471,11 @@ | ||
573 | sodipodi:cy="5.5" | 471 | sodipodi:cy="5.5" |
574 | sodipodi:rx="1" | 472 | sodipodi:rx="1" |
575 | sodipodi:ry="1" | 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 | transform="translate(0,1018.3622)" /> | 475 | transform="translate(0,1018.3622)" /> |
578 | <path | 476 | <path |
579 | transform="translate(0,1021.3622)" | 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 | sodipodi:ry="1" | 479 | sodipodi:ry="1" |
582 | sodipodi:rx="1" | 480 | sodipodi:rx="1" |
583 | sodipodi:cy="5.5" | 481 | sodipodi:cy="5.5" |
@@ -593,15 +491,16 @@ | @@ -593,15 +491,16 @@ | ||
593 | sodipodi:cy="5.5" | 491 | sodipodi:cy="5.5" |
594 | sodipodi:rx="1" | 492 | sodipodi:rx="1" |
595 | sodipodi:ry="1" | 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 | transform="translate(0,1024.3622)" /> | 495 | transform="translate(0,1024.3622)" /> |
598 | <path | 496 | <path |
599 | id="path4827" | 497 | id="path4827" |
600 | style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" | 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 | <path | 501 | <path |
603 | transform="translate(0,1033.3622)" | 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 | sodipodi:ry="1" | 504 | sodipodi:ry="1" |
606 | sodipodi:rx="1" | 505 | sodipodi:rx="1" |
607 | sodipodi:cy="5.5" | 506 | sodipodi:cy="5.5" |
@@ -617,11 +516,11 @@ | @@ -617,11 +516,11 @@ | ||
617 | sodipodi:cy="5.5" | 516 | sodipodi:cy="5.5" |
618 | sodipodi:rx="1" | 517 | sodipodi:rx="1" |
619 | sodipodi:ry="1" | 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 | transform="translate(0,1036.3622)" /> | 520 | transform="translate(0,1036.3622)" /> |
622 | <path | 521 | <path |
623 | transform="translate(0,1039.3622)" | 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 | sodipodi:ry="1" | 524 | sodipodi:ry="1" |
626 | sodipodi:rx="1" | 525 | sodipodi:rx="1" |
627 | sodipodi:cy="5.5" | 526 | sodipodi:cy="5.5" |
@@ -629,6 +528,201 @@ | @@ -629,6 +528,201 @@ | ||
629 | id="path4833" | 528 | id="path4833" |
630 | 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" | 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 | sodipodi:type="arc" /> | 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 | </g> | 726 | </g> |
633 | <g | 727 | <g |
634 | id="g4835" | 728 | id="g4835" |
plugins/shopping_cart/public/style.css
1 | @import url(colorbox/colorbox.css); | 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 | .product-item .cart-add-item { | 15 | .product-item .cart-add-item { |
@@ -13,16 +19,15 @@ | @@ -13,16 +19,15 @@ | ||
13 | .cart { | 19 | .cart { |
14 | position: fixed; | 20 | position: fixed; |
15 | right: 20px; | 21 | right: 20px; |
16 | - top: 0px; | 22 | + bottom: 0px; |
17 | width: 200px; | 23 | width: 200px; |
18 | z-index: 1000; | 24 | z-index: 1000; |
19 | border: 1px solid #777; | 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 | .cart h3 { | 29 | .cart h3 { |
25 | - color: #888; | 30 | + color: #000; |
26 | margin: 0px 0px 0px 5px; | 31 | margin: 0px 0px 0px 5px; |
27 | } | 32 | } |
28 | 33 | ||
@@ -108,7 +113,7 @@ | @@ -108,7 +113,7 @@ | ||
108 | padding: 0px 5px; | 113 | padding: 0px 5px; |
109 | } | 114 | } |
110 | .cart-toggle:hover { | 115 | .cart-toggle:hover { |
111 | - color: #555; | 116 | + color: #fff; |
112 | } | 117 | } |
113 | 118 | ||
114 | #cart-request-box { | 119 | #cart-request-box { |
@@ -120,6 +125,15 @@ | @@ -120,6 +125,15 @@ | ||
120 | float: left; | 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 | #cart-form-main { | 137 | #cart-form-main { |
124 | border: 2px solid #FFF; | 138 | border: 2px solid #FFF; |
125 | padding: 0px 10px; | 139 | padding: 0px 10px; |
@@ -171,8 +185,8 @@ label.error { | @@ -171,8 +185,8 @@ label.error { | ||
171 | 185 | ||
172 | .controller-profile_editor a.control-panel-shopping-cart-purchase-report {background-image: url(images/control-panel/purchase-report.png)} | 186 | .controller-profile_editor a.control-panel-shopping-cart-purchase-report {background-image: url(images/control-panel/purchase-report.png)} |
173 | .controller-profile_editor .msie6 a.control-panel-shopping-cart-purchase-report {background-image: url(images/control-panel/purchase-report.gif)} | 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 | .action-shopping_cart_plugin_myprofile-reports td.order-info { | 191 | .action-shopping_cart_plugin_myprofile-reports td.order-info { |
178 | padding: 0px; | 192 | padding: 0px; |
plugins/shopping_cart/views/cart.html.erb
1 | <div id="cart1" class="cart" style="display:none" | 1 | <div id="cart1" class="cart" style="display:none" |
2 | data-l10nRemoveItem="<%=_('Are you sure you want to remove this item?')%>" | 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 | <div class="cart-inner"> | 4 | <div class="cart-inner"> |
5 | <div class="cart-content"> | 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 | <ul class="cart-items"></ul> | 8 | <ul class="cart-items"></ul> |
9 | <div class="cart-total"><%=_('Total:')%> <b></b></div> | 9 | <div class="cart-total"><%=_('Total:')%> <b></b></div> |
10 | <a href="cart:buy" class="cart-buy"><%=_('Shopping checkout')%></a> | 10 | <a href="cart:buy" class="cart-buy"><%=_('Shopping checkout')%></a> |
11 | </div> | 11 | </div> |
12 | <a href="#" onclick="Cart.toggle(this); return false" class="cart-toggle"> | 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 | </a> | 15 | </a> |
16 | </div> | 16 | </div> |
17 | </div> | 17 | </div> |
plugins/shopping_cart/views/shopping_cart_plugin_myprofile/edit.html.erb
1 | -<h1> <%= _('Cart options') %> </h1> | 1 | +<h1> <%= _('Basket options') %> </h1> |
2 | 2 | ||
3 | <% form_for(:profile_attr, profile, :url => {:action => 'edit'}, :html => {:method => 'post'}) do |f| %> | 3 | <% form_for(:profile_attr, profile, :url => {:action => 'edit'}, :html => {:method => 'post'}) do |f| %> |
4 | <%= labelled_form_field(_('Enabled?'), f.check_box(:shopping_cart)) %> | 4 | <%= labelled_form_field(_('Enabled?'), f.check_box(:shopping_cart)) %> |
plugins/shopping_cart/views/shopping_cart_plugin_profile/buy.html.erb
@@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
17 | </div> | 17 | </div> |
18 | <% end %> | 18 | <% end %> |
19 | <%= items_table(session[:cart][:items], profile) %> | 19 | <%= items_table(session[:cart][:items], profile) %> |
20 | + <%= link_to '', '#', :onclick => "Cart.colorbox_close(this);", :class => 'cart-box-close icon-cancel' %> | ||
20 | </div> | 21 | </div> |
21 | 22 | ||
22 | <script type="text/javascript"> | 23 | <script type="text/javascript"> |
777 Bytes
public/javascripts/application.js
@@ -255,7 +255,7 @@ function toggleSubmenu(trigger, title, link_list) { | @@ -255,7 +255,7 @@ function toggleSubmenu(trigger, title, link_list) { | ||
255 | if (!hide) { | 255 | if (!hide) { |
256 | var direction = 'down'; | 256 | var direction = 'down'; |
257 | if (submenu.hasClass('up')) direction = 'up'; | 257 | if (submenu.hasClass('up')) direction = 'up'; |
258 | - submenu.show('slide', { 'direction' : direction }, 'slow'); | 258 | + jQuery(submenu).fadeIn(); |
259 | } | 259 | } |
260 | } | 260 | } |
261 | return false; | 261 | return false; |
@@ -283,18 +283,18 @@ function toggleSubmenu(trigger, title, link_list) { | @@ -283,18 +283,18 @@ function toggleSubmenu(trigger, title, link_list) { | ||
283 | content.append(list); | 283 | content.append(list); |
284 | submenu.append(header).append(content).append(footer); | 284 | submenu.append(header).append(content).append(footer); |
285 | jQuery(trigger).before(submenu); | 285 | jQuery(trigger).before(submenu); |
286 | - submenu.show('slide', { 'direction' : direction }, 'slow'); | 286 | + jQuery(submenu).fadeIn(); |
287 | } | 287 | } |
288 | 288 | ||
289 | function toggleMenu(trigger) { | 289 | function toggleMenu(trigger) { |
290 | hideAllSubmenus(); | 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 | function hideAllSubmenus() { | 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 | jQuery('#chat-online-users-content').hide(); | 298 | jQuery('#chat-online-users-content').hide(); |
299 | } | 299 | } |
300 | 300 | ||
@@ -694,3 +694,14 @@ jQuery(function() { | @@ -694,3 +694,14 @@ jQuery(function() { | ||
694 | target: "#ajax-form-message-area" | 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 @@ | @@ -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 @@ | @@ -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,10 +1075,12 @@ code input { | ||
1075 | text-align: left; | 1075 | text-align: left; |
1076 | background: transparent url(/images/black-alpha-pixel.png); | 1076 | background: transparent url(/images/black-alpha-pixel.png); |
1077 | border-bottom: 1px solid #333; | 1077 | border-bottom: 1px solid #333; |
1078 | + text-decoration: none; | ||
1078 | } | 1079 | } |
1079 | 1080 | ||
1080 | .zoomable-image:hover .zoomify-image { | 1081 | .zoomable-image:hover .zoomify-image { |
1081 | display: block; | 1082 | display: block; |
1083 | + text-decoration: none; | ||
1082 | } | 1084 | } |
1083 | 1085 | ||
1084 | #article .zoomify-image { | 1086 | #article .zoomify-image { |
@@ -1093,6 +1095,7 @@ code input { | @@ -1093,6 +1095,7 @@ code input { | ||
1093 | border-bottom: 1px solid #eee; | 1095 | border-bottom: 1px solid #eee; |
1094 | display: block; | 1096 | display: block; |
1095 | background: transparent url(/images/zoom.png) left center no-repeat; | 1097 | background: transparent url(/images/zoom.png) left center no-repeat; |
1098 | + color: #fff; | ||
1096 | } | 1099 | } |
1097 | 1100 | ||
1098 | #article pre { | 1101 | #article pre { |
@@ -2962,71 +2965,228 @@ div#activation_enterprise div { | @@ -2962,71 +2965,228 @@ div#activation_enterprise div { | ||
2962 | 2965 | ||
2963 | /* ==> public/stylesheets/controller_catalog.css <== */ | 2966 | /* ==> public/stylesheets/controller_catalog.css <== */ |
2964 | /* ==> @import url('products.css'); <== */ | 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 | margin: 0px; | 2972 | margin: 0px; |
2970 | padding: 0px; | 2973 | padding: 0px; |
2971 | } | 2974 | } |
2972 | - | ||
2973 | -#product_list ul { | 2975 | +#product-list ul { |
2974 | margin: 0px; | 2976 | margin: 0px; |
2975 | padding: 0px; | 2977 | padding: 0px; |
2976 | } | 2978 | } |
2977 | - | ||
2978 | -#content #product_list li { | 2979 | +#product-list li { |
2979 | margin: 0px; | 2980 | margin: 0px; |
2980 | padding: 0px; | 2981 | padding: 0px; |
2981 | list-style: none; | 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 | margin-bottom: 10px; | 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 | display: block; | 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 | float: left; | 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 | /* * * Show Product * * * * * * * * * * * * */ | 3192 | /* * * Show Product * * * * * * * * * * * * */ |
@@ -3223,6 +3383,86 @@ div#activation_enterprise div { | @@ -3223,6 +3383,86 @@ div#activation_enterprise div { | ||
3223 | font-weight: bold; | 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 | /* ==> public/stylesheets/controller_cms.css <== */ | 3466 | /* ==> public/stylesheets/controller_cms.css <== */ |
3227 | 3467 | ||
3228 | 3468 |
public/stylesheets/colorbox/colorbox.css
@@ -18,29 +18,29 @@ | @@ -18,29 +18,29 @@ | ||
18 | Change the following styles to modify the appearance of ColorBox. They are | 18 | Change the following styles to modify the appearance of ColorBox. They are |
19 | ordered & tabbed in a way that represents the nesting of the generated HTML. | 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 | #colorbox{} | 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 | #cboxContent{background:#fff; overflow:hidden;} | 31 | #cboxContent{background:#fff; overflow:hidden;} |
32 | #cboxError{padding:50px; border:1px solid #ccc;} | 32 | #cboxError{padding:50px; border:1px solid #ccc;} |
33 | #cboxLoadedContent{margin-bottom:28px;} | 33 | #cboxLoadedContent{margin-bottom:28px;} |
34 | #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} | 34 | #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} |
35 | #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} | 35 | #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} |
36 | #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;} | 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 | #cboxPrevious.hover{background-position:-75px -25px;} | 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 | #cboxNext.hover{background-position:-50px -25px;} | 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 | #cboxClose.hover{background-position:-25px -25px;} | 44 | #cboxClose.hover{background-position:-25px -25px;} |
45 | 45 | ||
46 | /* | 46 | /* |
@@ -61,14 +61,14 @@ | @@ -61,14 +61,14 @@ | ||
61 | /* | 61 | /* |
62 | The following provides PNG transparency support for IE6 | 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 | .cboxIE6 #cboxTopLeft, | 73 | .cboxIE6 #cboxTopLeft, |
74 | .cboxIE6 #cboxTopCenter, | 74 | .cboxIE6 #cboxTopCenter, |
script/sample-profiles
@@ -98,7 +98,7 @@ end | @@ -98,7 +98,7 @@ end | ||
98 | done | 98 | done |
99 | 99 | ||
100 | print "Activating users: " | 100 | print "Activating users: " |
101 | -User.all(:conditions => ['login NOT LIKE "%%_template"']).each do |user| | 101 | +User.all(:conditions => ["login NOT LIKE '%%_template'"]).each do |user| |
102 | user.activate | 102 | user.activate |
103 | print '.' | 103 | print '.' |
104 | end | 104 | end |
test/factories.rb
@@ -449,4 +449,12 @@ module Noosfero::Factory | @@ -449,4 +449,12 @@ module Noosfero::Factory | ||
449 | { :singular => 'Litre', :plural => 'Litres', :environment_id => 1 } | 449 | { :singular => 'Litre', :plural => 'Litres', :environment_id => 1 } |
450 | end | 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 | end | 460 | end |
13.4 KB
17.2 KB
test/functional/catalog_controller_test.rb
@@ -46,7 +46,7 @@ class CatalogControllerTest < ActionController::TestCase | @@ -46,7 +46,7 @@ class CatalogControllerTest < ActionController::TestCase | ||
46 | 46 | ||
47 | assert_equal 12, @enterprise.products.count | 47 | assert_equal 12, @enterprise.products.count |
48 | get :index, :profile => @enterprise.identifier | 48 | get :index, :profile => @enterprise.identifier |
49 | - assert_equal 10, assigns(:products).count | 49 | + assert_equal 9, assigns(:products).count |
50 | assert_tag :a, :attributes => {:class => 'next_page'} | 50 | assert_tag :a, :attributes => {:class => 'next_page'} |
51 | end | 51 | end |
52 | 52 | ||
@@ -63,21 +63,13 @@ class CatalogControllerTest < ActionController::TestCase | @@ -63,21 +63,13 @@ class CatalogControllerTest < ActionController::TestCase | ||
63 | should 'not show product price when listing products if not informed' do | 63 | should 'not show product price when listing products if not informed' do |
64 | prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) | 64 | prod = @enterprise.products.create!(:name => 'Product test', :product_category => @product_category) |
65 | get :index, :profile => @enterprise.identifier | 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 | end | 67 | end |
68 | 68 | ||
69 | should 'show product price when listing products if informed' do | 69 | should 'show product price when listing products if informed' do |
70 | prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category) | 70 | prod = @enterprise.products.create!(:name => 'Product test', :price => 50.00, :product_category => @product_category) |
71 | get :index, :profile => @enterprise.identifier | 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 | end | 73 | end |
82 | 74 | ||
83 | should 'add an zero width space every 4 caracters of comment urls' do | 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,4 +468,47 @@ class ManageProductsControllerTest < ActionController::TestCase | ||
468 | assert_response 403 | 468 | assert_response 403 |
469 | end | 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 | end | 514 | end |
test/unit/application_helper_test.rb
@@ -625,13 +625,18 @@ class ApplicationHelperTest < ActiveSupport::TestCase | @@ -625,13 +625,18 @@ class ApplicationHelperTest < ActiveSupport::TestCase | ||
625 | env = Environment.default | 625 | env = Environment.default |
626 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(false) | 626 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(false) |
627 | stubs(:environment).returns(env) | 627 | stubs(:environment).returns(env) |
628 | - assert_nil add_zoom_to_images | 628 | + assert_nil add_zoom_to_article_images |
629 | end | 629 | end |
630 | 630 | ||
631 | should 'return code when :show_zoom_button_on_article_images is enabled in environment' do | 631 | should 'return code when :show_zoom_button_on_article_images is enabled in environment' do |
632 | env = Environment.default | 632 | env = Environment.default |
633 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(true) | 633 | env.stubs(:enabled?).with(:show_zoom_button_on_article_images).returns(true) |
634 | stubs(:environment).returns(env) | 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 | assert_not_nil add_zoom_to_images | 640 | assert_not_nil add_zoom_to_images |
636 | end | 641 | end |
637 | 642 |
test/unit/enterprise_homepage_test.rb
@@ -16,43 +16,9 @@ class EnterpriseHomepageTest < ActiveSupport::TestCase | @@ -16,43 +16,9 @@ class EnterpriseHomepageTest < ActiveSupport::TestCase | ||
16 | assert_kind_of String, EnterpriseHomepage.description | 16 | assert_kind_of String, EnterpriseHomepage.description |
17 | end | 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 | end | 22 | end |
57 | 23 | ||
58 | should 'can display hits' do | 24 | should 'can display hits' do |
test/unit/enterprise_test.rb
@@ -446,4 +446,8 @@ class EnterpriseTest < ActiveSupport::TestCase | @@ -446,4 +446,8 @@ class EnterpriseTest < ActiveSupport::TestCase | ||
446 | assert_equal false, enterprise.receives_scrap_notification? | 446 | assert_equal false, enterprise.receives_scrap_notification? |
447 | end | 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 | end | 453 | end |
test/unit/environment_test.rb
@@ -1200,4 +1200,7 @@ class EnvironmentTest < ActiveSupport::TestCase | @@ -1200,4 +1200,7 @@ class EnvironmentTest < ActiveSupport::TestCase | ||
1200 | assert_not_includes environment.enabled_plugins, plugin | 1200 | assert_not_includes environment.enabled_plugins, plugin |
1201 | end | 1201 | end |
1202 | 1202 | ||
1203 | + should 'have production costs' do | ||
1204 | + assert_respond_to Environment.default, :production_costs | ||
1205 | + end | ||
1203 | end | 1206 | end |
test/unit/highlights_block_test.rb
@@ -77,6 +77,7 @@ class HighlightsBlockTest < ActiveSupport::TestCase | @@ -77,6 +77,7 @@ class HighlightsBlockTest < ActiveSupport::TestCase | ||
77 | file = mock() | 77 | file = mock() |
78 | UploadedFile.expects(:find).with(1).returns(file) | 78 | UploadedFile.expects(:find).with(1).returns(file) |
79 | file.expects(:public_filename).returns('address') | 79 | file.expects(:public_filename).returns('address') |
80 | + UploadedFile.expects(:find).with(0).returns(nil) | ||
80 | block = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => 'some', :position => '2', :title => 'Some'}]) | 81 | block = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => 'some', :position => '2', :title => 'Some'}]) |
81 | block.save! | 82 | block.save! |
82 | block.reload | 83 | block.reload |
@@ -115,6 +116,12 @@ class HighlightsBlockTest < ActiveSupport::TestCase | @@ -115,6 +116,12 @@ class HighlightsBlockTest < ActiveSupport::TestCase | ||
115 | f3 = mock() | 116 | f3 = mock() |
116 | f3.expects(:public_filename).returns('address') | 117 | f3.expects(:public_filename).returns('address') |
117 | UploadedFile.expects(:find).with(3).returns(f3) | 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 | block = HighlightsBlock.new | 125 | block = HighlightsBlock.new |
119 | i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'} | 126 | i1 = {:image_id => 1, :address => '/address', :position => 3, :title => 'address'} |
120 | i2 = {:image_id => 2, :address => '/address', :position => 1, :title => 'address'} | 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,4 +162,19 @@ class InputTest < ActiveSupport::TestCase | ||
162 | assert_kind_of Unit, input.build_unit | 162 | assert_kind_of Unit, input.build_unit |
163 | end | 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 | end | 180 | end |
@@ -0,0 +1,81 @@ | @@ -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,4 +382,132 @@ class ProductTest < ActiveSupport::TestCase | ||
382 | assert_includes Product.find_by_contents('thing'), p2 | 382 | assert_includes Product.find_by_contents('thing'), p2 |
383 | end | 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 | end | 513 | end |
@@ -0,0 +1,102 @@ | @@ -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 |