How to avoid sale order automaticaly created for public user in the website shop?

Pascal Tremblay

Hello there,

We have a site on Odoo 8. The shop works well at http://cferalma.com/shop. 

But it is only a catalog. Users can't buy on this site. No "add to cart" button, nowhere.

But sometimes (often), sale order are created for the public user in the sales. We don't want these sale orders.

I will publish below our solution for this problem. May be it could help somebody.

Thanks to comment.

2 Respostas
Pascal Tremblay
Melhor Resposta

Here is our solution. We hope it could help somebody.

I hope you could comment this solution! May be we are not right.


Since there is no link for these 6 links on our website, we want they become inaccessible, even if they are written directly in browser address bar :







We are pretty sure that this is the problem for all those sale orders automatically created. So we don't want those links appear in search engine. More, we also don't want those links work at all if the user write it in directly in his browser address bar.

First move : modify the robots.txt file

In a custom module, we put this code :

<?xml version="1.0" encoding="UTF-8"?>

<template id="website.robots">

User-agent: *

Disallow: /shop/cart

Disallow: /shop/payment/validate

Disallow: /shop/confirm_order

Disallow: /shop/confirmation

Disallow: /shop/payment

Disallow: /shop/checkout

Sitemap:<t t-esc="url_root"/>sitemap.xml




Second move : modify the sitemap.xml

We override the enumerate_pages method of the website class :

import logging

logger = logging.getLogger(__name__)

from openerp.osv import osv

from openerp.addons.web.http import request

class website(osv.osv):

_inherit = "website"

def enumerate_pages(self, cr, uid, ids, query_string=None, context=None):

logger.error("enumerate_pages BEGIN")

""" Available pages in the website/CMS. This is mostly used for links

generation and can be overridden by modules setting up new HTML

controllers for dynamic pages (e.g. blog).

By default, returns template views marked as pages.

:param str query_string: a (user-provided) string, fetches pages

matching the string

:returns: a list of mappings with two keys: ``name`` is the displayable

name of the resource (page), ``url`` is the absolute URL

of the same.

:rtype: list({name: str, url: str})


router = request.httprequest.app.get_db_router(request.db)

# Force enumeration to be performed as public user

url_list = []

for rule in router.iter_rules():

if not self.rule_is_enumerable(rule):


converters = rule._converters or {}

if query_string and not converters and (query_string not in rule.build([{}], append_unknown=False)[1]):


values = [{}]

convitems = converters.items()

# converters with a domain are processed after the other ones

gd = lambda x: hasattr(x[1], 'domain') and (x[1].domain <> '[]')

convitems.sort(lambda x, y: cmp(gd(x), gd(y)))

for (i,(name, converter)) in enumerate(convitems):

newval = []

for val in values:

query = i==(len(convitems)-1) and query_string

for v in converter.generate(request.cr, uid, query=query, args=val, context=context):

newval.append( val.copy() )

v[name] = v['loc']

del v['loc']


values = newval

logger.error(" values :: %s", str(values))

for value in values:

domain_part, url = rule.build(value, append_unknown=False)

page = {'loc': url}

for key,val in value.items():

if key.startswith('__'):

page[key[2:]] = val


if url in ('/sitemap.xml','/shop/cart','/shop/payment','/shop/payment/validate','/shop/confirm_order','/shop/confirmation','/shop/checkout',):

logger.error(" this url was avoid : %s",str(url))


if url in url_list:



logger.error(" page :: %s", str(page))

yield page

Third move : redirect url in nginx

upstream odoo-cfer {



server {

listen 80;

server_name cferalma.com;

location / {

proxy_pass http://odoo-cfer;

proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

proxy_redirect off;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto https;


location ~* /web/static/ {

proxy_cache_valid 200 60m;

proxy_buffering on;

expires 864000;

proxy_pass http://odoo-cfer;


location = /shop/cart {

return 301 http://cferalma.com/shop;


location = /shop/payment/validate {

return 301 http://cferalma.com/shop;


location = /shop/confirm_order {

return 301 http://cferalma.com/shop;


location = /shop/confirmation {

return 301 http://cferalma.com/shop;


location = /shop/payment {

return 301 http://cferalma.com/shop;


location = /shop/checkout {

return 301 http://cferalma.com/shop;


error_page 502 /502.html;

location = /502.html {

root /usr/share/nginx/html;



Fatih Piristine
Melhor Resposta

rewriting the controller in a custom module would be way handier. no need to bubble up the webserver conf.

also adding a column to website model would make easier to configure for later use of excluding things from sitemaps.

class website(osv.osv):
_inherit = 'website'

_columns = {
'google_tags_manager_key': fields.char('Google Tags Manager'),
'exclude_from_sitemap': fields.text('Exclude from sitemap')

def enumerate_pages ( ... )
    exclude_from_sitemap = []

    if current_website.exclude_from_sitemap:
    exclude_from_sitemap = current_website.exclude_from_sitemap.splitlines()

if url in ('/sitemap.xml',) or url in exclude_from_sitemap:
if url in url_list:
if not published:

yield page