diff --git a/website_seo/core/__init__.py b/website_seo/core/__init__.py
index 89c2485..9d60a1a 100755
--- a/website_seo/core/__init__.py
+++ b/website_seo/core/__init__.py
@@ -18,4 +18,4 @@
# along with this program. If not, see .
#
##############################################################################
-import core
+from . import core
diff --git a/website_seo_blog/__init__.py b/website_seo_blog/__init__.py
index f647841..efa4fe9 100755
--- a/website_seo_blog/__init__.py
+++ b/website_seo_blog/__init__.py
@@ -18,6 +18,6 @@
# along with this program. If not, see .
#
##############################################################################
-import controllers
-import models
-import tests
+from . import controllers
+from . import models
+from . import tests
diff --git a/website_seo_blog/tests/__init__.py b/website_seo_blog/tests/__init__.py
index 5cd6799..7084442 100755
--- a/website_seo_blog/tests/__init__.py
+++ b/website_seo_blog/tests/__init__.py
@@ -18,5 +18,5 @@
# along with this program. If not, see .
#
##############################################################################
-import test_website_seo_blog
-import test_website_seo_blog_controller
+from . import test_website_seo_blog
+from . import test_website_seo_blog_controller
diff --git a/website_seo_blog/tests/test_website_seo_blog_controller.py b/website_seo_blog/tests/test_website_seo_blog_controller.py
index a9edd9e..9e89afa 100755
--- a/website_seo_blog/tests/test_website_seo_blog_controller.py
+++ b/website_seo_blog/tests/test_website_seo_blog_controller.py
@@ -1,6 +1,26 @@
# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
import openerp
+
ODOO_NOT_FOUND_MESSAGE = '404: Page not found!'
diff --git a/website_seo_sale/README.rst b/website_seo_sale/README.rst
new file mode 100755
index 0000000..e69de29
diff --git a/website_seo_sale/__init__.py b/website_seo_sale/__init__.py
new file mode 100644
index 0000000..c8f6e41
--- /dev/null
+++ b/website_seo_sale/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from . import controllers
+from . import models
diff --git a/website_seo_sale/__openerp__.py b/website_seo_sale/__openerp__.py
new file mode 100644
index 0000000..ef1df35
--- /dev/null
+++ b/website_seo_sale/__openerp__.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+{
+ 'name': 'eCommerce SEO Optimized',
+ 'category': 'Website',
+ 'sequence': 55,
+ 'summary': 'Sell Your Products Online',
+ 'website': 'http://www.bloopark.de',
+ 'version': '1.0',
+ 'author': "bloopark systems GmbH & Co. KG ,"
+ "Odoo Community Association (OCA)",
+ 'description': """
+OpenERP E-Commerce SEO Optimized
+==================
+
+ """,
+ 'depends': ['website_seo', 'website_sale'],
+ 'data': [
+ 'views/templates.xml',
+ ],
+ 'installable': True,
+ 'application': False,
+}
diff --git a/website_seo_sale/controllers/__init__.py b/website_seo_sale/controllers/__init__.py
new file mode 100644
index 0000000..0b4a657
--- /dev/null
+++ b/website_seo_sale/controllers/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from . import main
diff --git a/website_seo_sale/controllers/main.py b/website_seo_sale/controllers/main.py
new file mode 100644
index 0000000..9cd58c4
--- /dev/null
+++ b/website_seo_sale/controllers/main.py
@@ -0,0 +1,211 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+import werkzeug
+
+from openerp import http
+from openerp.http import request
+from openerp.addons.website_sale.controllers.main import website_sale, PPG, PPR, QueryURL, table_compute
+from openerp.addons.website_seo_sale.models.product import slug
+from openerp.tools.translate import _
+
+
+class WebsiteSeoSale(website_sale):
+
+ @http.route([
+ '/shop',
+ '/category/',
+ '/shop/category/',
+ ], type='http', auth="public", website=True)
+ def shop(self, page=0, category=None, search='', ppg=False, **post):
+
+ cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
+ domain = request.website.sale_product_domain()
+
+ if ppg:
+ try:
+ ppg = int(ppg)
+ except ValueError:
+ ppg = PPG
+ post["ppg"] = ppg
+ else:
+ ppg = PPG
+
+ if search:
+ for srch in search.split(" "):
+ domain += ['|', '|', '|', ('name', 'ilike', srch), ('description', 'ilike', srch),
+ ('description_sale', 'ilike', srch), ('product_variant_ids.default_code', 'ilike', srch)]
+ if category:
+ domain += [('public_categ_ids', 'child_of', int(category))]
+ attrib_list = request.httprequest.args.getlist('attrib')
+ attrib_values = [map(int,v.split("-")) for v in attrib_list if v]
+ attrib_set = set([v[1] for v in attrib_values])
+
+ if attrib_values:
+ attrib = None
+ ids = []
+ for value in attrib_values:
+ if not attrib:
+ attrib = value[0]
+ ids.append(value[1])
+ elif value[0] == attrib:
+ ids.append(value[1])
+ else:
+ domain += [('attribute_line_ids.value_ids', 'in', ids)]
+ attrib = value[0]
+ ids = [value[1]]
+ if attrib:
+ domain += [('attribute_line_ids.value_ids', 'in', ids)]
+
+ keep = QueryURL('/shop', category=category and int(category), search=search, attrib=attrib_list)
+
+ if not context.get('pricelist'):
+ pricelist = self.get_pricelist()
+ context['pricelist'] = int(pricelist)
+ else:
+ pricelist = pool.get('product.pricelist').browse(cr, uid, context['pricelist'], context)
+ url = "/"
+ if search:
+ post["search"] = search
+ if category:
+ category = pool['product.public.category'].browse(cr, uid, int(category), context=context)
+ url = "/%s" % slug(category)
+ if attrib_list:
+ post['attrib'] = attrib_list
+
+ style_obj = pool['product.style']
+ style_ids = style_obj.search(cr, uid, [], context=context)
+ styles = style_obj.browse(cr, uid, style_ids, context=context)
+
+ category_obj = pool['product.public.category']
+ category_ids = category_obj.search(cr, uid, [('parent_id', '=', False)], context=context)
+ categs = category_obj.browse(cr, uid, category_ids, context=context)
+
+ product_obj = pool.get('product.template')
+
+ parent_category_ids = []
+ if category:
+ parent_category_ids = [category.id]
+ current_category = category
+ while current_category.parent_id:
+ parent_category_ids.append(current_category.parent_id.id)
+ current_category = current_category.parent_id
+
+ product_count = product_obj.search_count(cr, uid, domain, context=context)
+ pager = request.website.pager(url=url, total=product_count, page=page, step=ppg, scope=7, url_args=post)
+ product_ids = product_obj.search(cr, uid, domain, limit=ppg, offset=pager['offset'], order='website_published desc, website_sequence asc', context=context)
+ products = product_obj.browse(cr, uid, product_ids, context=context)
+
+ attributes_obj = request.registry['product.attribute']
+ attributes_ids = attributes_obj.search(cr, uid, [('attribute_line_ids.product_tmpl_id', 'in', product_ids)], context=context)
+ attributes = attributes_obj.browse(cr, uid, attributes_ids, context=context)
+
+ from_currency = pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
+ to_currency = pricelist.currency_id
+ compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
+
+ values = {
+ 'search': search,
+ 'category': category,
+ 'attrib_values': attrib_values,
+ 'attrib_set': attrib_set,
+ 'pager': pager,
+ 'pricelist': pricelist,
+ 'products': products,
+ 'bins': table_compute().process(products, ppg),
+ 'rows': PPR,
+ 'styles': styles,
+ 'categories': categs,
+ 'attributes': attributes,
+ 'compute_currency': compute_currency,
+ 'keep': keep,
+ 'parent_category_ids': parent_category_ids,
+ 'style_in_product': lambda style, product: style.id in [s.id for s in product.website_style_ids],
+ 'attrib_encode': lambda attribs: werkzeug.url_encode([('attrib',i) for i in attribs]),
+ }
+ if category:
+ values['main_object'] = category
+ return request.website.render("website_sale.products", values)
+
+ @http.route(['/'], type='http', auth="public", website=True)
+ def product(self, product, category='', search='', **kwargs):
+ cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
+ category_obj = pool['product.public.category']
+ template_obj = pool['product.template']
+
+ context.update(active_id=product.id)
+
+ if category:
+ category = category_obj.browse(cr, uid, int(category), context=context)
+ category = category if category.exists() else False
+
+ attrib_list = request.httprequest.args.getlist('attrib')
+ attrib_values = [map(int,v.split("-")) for v in attrib_list if v]
+ attrib_set = set([v[1] for v in attrib_values])
+
+ keep = QueryURL('/shop', category=category and category.id, search=search, attrib=attrib_list)
+
+ category_ids = category_obj.search(cr, uid, [('parent_id', '=', False)], context=context)
+ categs = category_obj.browse(cr, uid, category_ids, context=context)
+
+ pricelist = self.get_pricelist()
+
+ from_currency = pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id
+ to_currency = pricelist.currency_id
+ compute_currency = lambda price: pool['res.currency']._compute(cr, uid, from_currency, to_currency, price, context=context)
+
+ # get the rating attached to a mail.message, and the rating stats of the product
+ Rating = pool['rating.rating']
+ rating_ids = Rating.search(cr, uid, [('message_id', 'in', product.website_message_ids.ids)], context=context)
+ ratings = Rating.browse(cr, uid, rating_ids, context=context)
+ rating_message_values = dict([(record.message_id.id, record.rating) for record in ratings])
+ rating_product = product.rating_get_stats([('website_published', '=', True)])
+
+ if not context.get('pricelist'):
+ context['pricelist'] = int(self.get_pricelist())
+ product = template_obj.browse(cr, uid, int(product), context=context)
+
+ values = {
+ 'search': search,
+ 'category': category,
+ 'pricelist': pricelist,
+ 'attrib_values': attrib_values,
+ 'compute_currency': compute_currency,
+ 'attrib_set': attrib_set,
+ 'keep': keep,
+ 'categories': categs,
+ 'main_object': product,
+ 'product': product,
+ 'get_attribute_value_ids': self.get_attribute_value_ids,
+ 'rating_message_values': rating_message_values,
+ 'rating_product': rating_product
+ }
+ return request.website.render("website_sale.product", values)
+
+ @http.route(['/shop/add_product'], type='http', auth="user", methods=['POST'], website=True)
+ def add_product(self, name=None, category=0, **post):
+ cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
+ if not name:
+ name = _("New Product")
+ product_obj = request.registry.get('product.product')
+ product_id = product_obj.create(cr, uid, { 'name': name, 'public_categ_ids': category }, context=context)
+ product = product_obj.browse(cr, uid, product_id, context=context)
+
+ return request.redirect("/%s?enable_editor=1" % slug(product.product_tmpl_id))
\ No newline at end of file
diff --git a/website_seo_sale/models/__init__.py b/website_seo_sale/models/__init__.py
new file mode 100644
index 0000000..244dab4
--- /dev/null
+++ b/website_seo_sale/models/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from . import ir_http
+from . import ir_ui_view
+from . import product
diff --git a/website_seo_sale/models/ir_http.py b/website_seo_sale/models/ir_http.py
new file mode 100644
index 0000000..e29bac8
--- /dev/null
+++ b/website_seo_sale/models/ir_http.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from openerp.osv import orm
+from openerp.addons.website.models.ir_http import ModelConverter, RequestUID
+from openerp.addons.website_seo_sale.models.product import slug, _UNSLUG_RE
+from openerp.http import request
+import re
+
+
+class IrHttp(orm.TransientModel):
+ _inherit = 'ir.http'
+
+ def _get_converters(self):
+ res = super(IrHttp, self)._get_converters()
+ res['model'] = UnderscoredModelConverter
+ return res
+
+class UnderscoredModelConverter(ModelConverter):
+
+ def __init__(self, url_map, model=False, domain='[]'):
+ super(ModelConverter, self).__init__(url_map, model)
+ self.domain = domain
+ self.regex = _UNSLUG_RE.pattern
+
+ def to_url(self, value):
+ return slug(value)
+
+ def to_python(self, value):
+ m = re.match(self.regex, value)
+ _uid = RequestUID(value=value, match=m, converter=self)
+
+ res = request.registry[self.model].search(request.cr, 1, [('name', '=', value.replace('_', ' '))])
+ if res:
+ return request.registry[self.model].browse(request.cr, _uid, res, context=request.context)
\ No newline at end of file
diff --git a/website_seo_sale/models/ir_ui_view.py b/website_seo_sale/models/ir_ui_view.py
new file mode 100755
index 0000000..e25ea13
--- /dev/null
+++ b/website_seo_sale/models/ir_ui_view.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from openerp import api, models
+from openerp.addons.website_seo_sale.models.product import slug
+
+
+class View(models.Model):
+
+ """Update view model with additional SEO variables."""
+
+ _name = 'ir.ui.view'
+ _inherit = ['ir.ui.view', 'website.seo.metadata']
+
+
+ @api.cr_uid_ids_context
+ def render(self, cr, uid, id_or_xml_id, values=None, engine='ir.qweb', context=None):
+ """Add additional helper variables.
+
+ Add slug function with additional seo url handling and the query string
+ of the http request environment to the values object.
+ """
+ if values is None:
+ values = {}
+
+ values.update({
+ 'slaag': slug,
+ })
+
+ return super(View, self).render(cr, uid, id_or_xml_id, values=values,
+ engine=engine, context=context)
diff --git a/website_seo_sale/models/product.py b/website_seo_sale/models/product.py
new file mode 100644
index 0000000..5456456
--- /dev/null
+++ b/website_seo_sale/models/product.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from openerp.osv import osv
+from openerp.osv import orm
+import re
+from openerp.tools.translate import _
+from openerp.exceptions import ValidationError
+
+
+_UNSLUG_RE = re.compile(r'(?:(\w{1,2}|\w[A-Za-z0-9-_]+?\w))(?=$|/)')
+
+def slug(value):
+ if isinstance(value, orm.browse_record):
+ name = value.display_name
+ else:
+ name = value
+
+ return name.replace(' ', '_')
+
+
+class ProductTemplate(osv.Model):
+ _inherit = ["product.template", "website.seo.metadata", 'website.published.mixin', 'rating.mixin']
+ _order = 'website_published desc, website_sequence desc, name'
+ _name = 'product.template'
+ _mail_post_access = 'read'
+
+ def _website_url(self, cr, uid, ids, field_name, arg, context=None):
+ res = super(product_template, self)._website_url(cr, uid, ids, field_name, arg, context=context)
+ for product in self.browse(cr, uid, ids, context=context):
+ res[product.id] = "/%s" % slug(product.name)
+ return res
+
+
+class ProductProduct(osv.Model):
+ _inherit = "product.product"
+
+ def open_website_url(self, cr, uid, ids, context=None):
+ template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
+ return self.pool['product.template'].open_website_url(cr, uid, [template_id], context=context)
+
+ def website_publish_button(self, cr, uid, ids, context=None):
+ template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
+ return self.pool['product.template'].website_publish_button(cr, uid, [template_id], context=context)
+
+ def website_publish_button(self, cr, uid, ids, context=None):
+ template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
+ return self.pool['product.template'].website_publish_button(cr, uid, [template_id], context=context)
+
+ def validate_seo_url(self, seo_url):
+ """Validate a manual entered SEO url."""
+ if not seo_url or not bool(re.match('^([.a-zA-Z0-9-_]+)$', seo_url)):
+ raise ValidationError(_('Only a-z, A-Z, 0-9, - and _ are allowed '
+ 'characters for the SEO url.'))
+ return True
+
+
+class ProductPublicCategory(osv.osv):
+ _inherit = ["product.public.category"]
+
+ def name_get(self, cr, uid, ids, context=None):
+ res = []
+ for cat in self.browse(cr, uid, ids, context=context):
+ res.append((cat.id, cat.name))
+ return res
\ No newline at end of file
diff --git a/website_seo_sale/tests/__init__.py b/website_seo_sale/tests/__init__.py
new file mode 100644
index 0000000..382d76a
--- /dev/null
+++ b/website_seo_sale/tests/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from . import test_website_seo_sale
diff --git a/website_seo_sale/tests/test_website_seo_sale.py b/website_seo_sale/tests/test_website_seo_sale.py
new file mode 100644
index 0000000..87c2f35
--- /dev/null
+++ b/website_seo_sale/tests/test_website_seo_sale.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Odoo, an open source suite of business apps
+# This module copyright (C) 2015 bloopark systems ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+import openerp.tests
+from openerp.addons.website_seo_sale.models.product import slug
+
+
+@openerp.tests.common.at_install(False)
+@openerp.tests.common.post_install(True)
+class TestWebsiteSeoSale(openerp.tests.common.TransactionCase):
+ def test_slug_product(self):
+ self.assertEqual(slug('Test Product'), 'Test_Product')
+
+ def test_product_url(self):
+ self.assertTrue(self.env['product.product'].validate_seo_url('Sample_Product'))
diff --git a/website_seo_sale/views/templates.xml b/website_seo_sale/views/templates.xml
new file mode 100644
index 0000000..dfc8073
--- /dev/null
+++ b/website_seo_sale/views/templates.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+ - Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New Product
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file