summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Dony <odo@openerp.com>2014-07-05 01:28:19 +0200
committerOlivier Dony <odo@openerp.com>2014-07-05 01:28:19 +0200
commitd9cda97cf47f78bff309aff2e6adff5808f9734d (patch)
tree3bbba24b15b7d0901d5bf82fed3b1dc07f72c6b3
parentf0ef8ac446115c0cb40a07a3792095c76d45c8e2 (diff)
parent5ceded9d69b3c261e501500e760b9b345bb77ecc (diff)
[MERGE] Forward-port saas-4 up to 5ceded9
-rw-r--r--addons/auth_oauth/controllers/main.py3
-rw-r--r--addons/auth_signup/res_users.py8
-rw-r--r--addons/document/document.py12
-rw-r--r--addons/hr_holidays/hr_holidays.py4
-rw-r--r--addons/l10n_multilang/__openerp__.py2
-rw-r--r--addons/mail/static/src/css/mail.css8
-rw-r--r--addons/mail/static/src/xml/mail.xml2
-rw-r--r--addons/mass_mailing/models/mass_mailing.py96
-rw-r--r--addons/project_issue_sheet/project_issue_sheet_view.xml1
-rw-r--r--addons/stock/stock.py14
-rw-r--r--addons/survey/survey.py6
-rw-r--r--addons/web_linkedin/web_linkedin.py2
-rw-r--r--addons/website/models/ir_http.py6
-rw-r--r--addons/website/models/website.py16
-rw-r--r--addons/website/tests/test_converter.py22
-rw-r--r--addons/website/views/website_templates.xml2
-rw-r--r--addons/website_crm/controllers/main.py2
-rw-r--r--addons/website_crm_partner_assign/controllers/main.py8
-rw-r--r--addons/website_customer/controllers/main.py8
-rw-r--r--addons/website_event/controllers/main.py11
-rw-r--r--addons/website_membership/controllers/main.py8
-rw-r--r--openerp/addons/base/res/res_partner.py2
-rw-r--r--openerp/addons/base/res/res_partner_view.xml4
-rw-r--r--openerp/report/render/rml2pdf/trml2pdf.py10
24 files changed, 157 insertions, 100 deletions
diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py
index 7652420d7c6..1a166c39cde 100644
--- a/addons/auth_oauth/controllers/main.py
+++ b/addons/auth_oauth/controllers/main.py
@@ -49,7 +49,8 @@ class OAuthLogin(Home):
def list_providers(self):
try:
provider_obj = request.registry.get('auth.oauth.provider')
- providers = provider_obj.search_read(request.cr, SUPERUSER_ID, [('enabled', '=', True)])
+ providers = provider_obj.search_read(request.cr, SUPERUSER_ID, [('enabled', '=', True), ('auth_endpoint', '!=', False), ('validation_endpoint', '!=', False)])
+ # TODO in forwardport: remove conditions on 'auth_endpoint' and 'validation_endpoint' when these fields will be 'required' in model
except Exception:
providers = []
for provider in providers:
diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py
index 5a744c21c81..576a778be45 100644
--- a/addons/auth_signup/res_users.py
+++ b/addons/auth_signup/res_users.py
@@ -201,6 +201,14 @@ class res_users(osv.Model):
partner.write({'signup_token': False, 'signup_type': False, 'signup_expiration': False})
partner_user = partner.user_ids and partner.user_ids[0] or False
+
+ # avoid overwriting existing (presumably correct) values with geolocation data
+ if partner.country_id or partner.zip or partner.city:
+ values.pop('city', None)
+ values.pop('country_id', None)
+ if partner.lang:
+ values.pop('lang', None)
+
if partner_user:
# user exists, modify it according to values
values.pop('login', None)
diff --git a/addons/document/document.py b/addons/document/document.py
index 9008f32cd20..47c30de7ca6 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -235,18 +235,8 @@ class document_directory(osv.osv):
_parent(dir_id, path)
return path
- def _check_recursion(self, cr, uid, ids, context=None):
- level = 100
- while len(ids):
- cr.execute('select distinct parent_id from document_directory where id in ('+','.join(map(str,ids))+')')
- ids = filter(None, map(lambda x:x[0], cr.fetchall()))
- if not level:
- return False
- level -= 1
- return True
-
_constraints = [
- (_check_recursion, 'Error! You cannot create recursive directories.', ['parent_id'])
+ (osv.osv._check_recursion, 'Error! You cannot create recursive directories.', ['parent_id'])
]
def onchange_content_id(self, cr, uid, ids, ressource_type_id):
diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py
index ed25b75aa83..d38cb705339 100644
--- a/addons/hr_holidays/hr_holidays.py
+++ b/addons/hr_holidays/hr_holidays.py
@@ -522,8 +522,8 @@ class hr_employee(osv.osv):
where
h.state='validate' and
s.limit=False and
- h.employee_id in (%s)
- group by h.employee_id"""% (','.join(map(str,ids)),) )
+ h.employee_id in %s
+ group by h.employee_id""", (tuple(ids),))
res = cr.dictfetchall()
remaining = {}
for r in res:
diff --git a/addons/l10n_multilang/__openerp__.py b/addons/l10n_multilang/__openerp__.py
index 5c91e1472c4..0b804c27263 100644
--- a/addons/l10n_multilang/__openerp__.py
+++ b/addons/l10n_multilang/__openerp__.py
@@ -32,7 +32,7 @@
templates to target objects.
""",
'website': 'http://www.openerp.com',
- 'depends' : ['account_accountant'],
+ 'depends' : ['account'],
'data': [],
'demo': [],
'installable': True,
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index 0abd8ab1b4e..0faf7fc5e0d 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -164,15 +164,9 @@
border-radius: 3px;
margin: 0px;
padding-left: 3px;
- padding-right: 15px;
+ padding-right: 5px;
margin-right: 5px;
}
-.openerp .oe_mail .oe_mail_vote_count .oe_e{
- position: absolute;
- bottom: 1px;
- right: 2px;
- font-size: 26px;
-}
/* c) Message action icons */
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index 3aea4a19555..116665724a9 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -344,7 +344,7 @@
<span t-name="mail.thread.message.vote">
<span class="oe_mail_vote_count" t-if='widget.vote_nb > 0'>
<t t-esc='widget.vote_nb' />
- <span class='oe_e'>8</span>
+ <i class="fa fa-thumbs-o-up"></i>
</span>
<a href='#' class="oe_msg_vote">
<t t-if="!widget.has_voted">like</t>
diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py
index d1c3e7facd4..a1077a3fffa 100644
--- a/addons/mass_mailing/models/mass_mailing.py
+++ b/addons/mass_mailing/models/mass_mailing.py
@@ -113,26 +113,38 @@ class MassMailingCampaign(osv.Model):
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
""" Compute statistics of the mass mailing campaign """
- Statistics = self.pool['mail.mail.statistics']
- results = dict.fromkeys(ids, False)
- for cid in ids:
- stat_ids = Statistics.search(cr, uid, [('mass_mailing_campaign_id', '=', cid)], context=context)
- stats = Statistics.browse(cr, uid, stat_ids, context=context)
- results[cid] = {
- 'total': len(stats),
- 'failed': len([s for s in stats if not s.scheduled is False and s.sent is False and not s.exception is False]),
- 'scheduled': len([s for s in stats if not s.scheduled is False and s.sent is False and s.exception is False]),
- 'sent': len([s for s in stats if not s.sent is False]),
- 'opened': len([s for s in stats if not s.opened is False]),
- 'replied': len([s for s in stats if not s.replied is False]),
- 'bounced': len([s for s in stats if not s.bounced is False]),
- }
- results[cid]['delivered'] = results[cid]['sent'] - results[cid]['bounced']
- results[cid]['received_ratio'] = 100.0 * results[cid]['delivered'] / (results[cid]['total'] or 1)
- results[cid]['opened_ratio'] = 100.0 * results[cid]['opened'] / (results[cid]['total'] or 1)
- results[cid]['replied_ratio'] = 100.0 * results[cid]['replied'] / (results[cid]['total'] or 1)
+ results = {}
+ cr.execute("""
+ SELECT
+ c.id as campaign_id,
+ COUNT(s.id) AS total,
+ COUNT(CASE WHEN s.sent is not null THEN 1 ELSE null END) AS sent,
+ COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is null THEN 1 ELSE null END) AS scheduled,
+ COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is not null THEN 1 ELSE null END) AS failed,
+ COUNT(CASE WHEN s.id is not null AND s.bounced is null THEN 1 ELSE null END) AS delivered,
+ COUNT(CASE WHEN s.opened is not null THEN 1 ELSE null END) AS opened,
+ COUNT(CASE WHEN s.replied is not null THEN 1 ELSE null END) AS replied ,
+ COUNT(CASE WHEN s.bounced is not null THEN 1 ELSE null END) AS bounced
+ FROM
+ mail_mail_statistics s
+ RIGHT JOIN
+ mail_mass_mailing_campaign c
+ ON (c.id = s.mass_mailing_campaign_id)
+ WHERE
+ c.id IN %s
+ GROUP BY
+ c.id
+ """, (tuple(ids), ))
+ for row in cr.dictfetchall():
+ results[row.pop('campaign_id')] = row
+ total = row['total'] or 1
+ row['delivered'] = row['sent'] - row['bounced']
+ row['received_ratio'] = 100.0 * row['delivered'] / total
+ row['opened_ratio'] = 100.0 * row['opened'] / total
+ row['replied_ratio'] = 100.0 * row['replied'] / total
return results
+
_columns = {
'name': fields.char('Name', required=True),
'stage_id': fields.many2one('mail.mass_mailing.stage', 'Stage', required=True),
@@ -283,26 +295,38 @@ class MassMailing(osv.Model):
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
""" Compute statistics of the mass mailing campaign """
- Statistics = self.pool['mail.mail.statistics']
- results = dict.fromkeys(ids, False)
- for mid in ids:
- stat_ids = Statistics.search(cr, uid, [('mass_mailing_id', '=', mid)], context=context)
- stats = Statistics.browse(cr, uid, stat_ids, context=context)
- results[mid] = {
- 'total': len(stats),
- 'failed': len([s for s in stats if not s.scheduled is False and s.sent is False and not s.exception is False]),
- 'scheduled': len([s for s in stats if not s.scheduled is False and s.sent is False and s.exception is False]),
- 'sent': len([s for s in stats if not s.sent is False]),
- 'opened': len([s for s in stats if not s.opened is False]),
- 'replied': len([s for s in stats if not s.replied is False]),
- 'bounced': len([s for s in stats if not s.bounced is False]),
- }
- results[mid]['delivered'] = results[mid]['sent'] - results[mid]['bounced']
- results[mid]['received_ratio'] = 100.0 * results[mid]['delivered'] / (results[mid]['total'] or 1)
- results[mid]['opened_ratio'] = 100.0 * results[mid]['opened'] / (results[mid]['total'] or 1)
- results[mid]['replied_ratio'] = 100.0 * results[mid]['replied'] / (results[mid]['total'] or 1)
+ results = {}
+ cr.execute("""
+ SELECT
+ m.id as mailing_id,
+ COUNT(s.id) AS total,
+ COUNT(CASE WHEN s.sent is not null THEN 1 ELSE null END) AS sent,
+ COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is null THEN 1 ELSE null END) AS scheduled,
+ COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is not null THEN 1 ELSE null END) AS failed,
+ COUNT(CASE WHEN s.id is not null AND s.bounced is null THEN 1 ELSE null END) AS delivered,
+ COUNT(CASE WHEN s.opened is not null THEN 1 ELSE null END) AS opened,
+ COUNT(CASE WHEN s.replied is not null THEN 1 ELSE null END) AS replied ,
+ COUNT(CASE WHEN s.bounced is not null THEN 1 ELSE null END) AS bounced
+ FROM
+ mail_mail_statistics s
+ RIGHT JOIN
+ mail_mass_mailing m
+ ON (m.id = s.mass_mailing_id)
+ WHERE
+ m.id IN %s
+ GROUP BY
+ m.id
+ """, (tuple(ids), ))
+ for row in cr.dictfetchall():
+ results[row.pop('mailing_id')] = row
+ total = row['total'] or 1
+ row['delivered'] = row['sent'] - row['bounced']
+ row['received_ratio'] = 100.0 * row['delivered'] / total
+ row['opened_ratio'] = 100.0 * row['opened'] / total
+ row['replied_ratio'] = 100.0 * row['replied'] / total
return results
+
def _get_mailing_model(self, cr, uid, context=None):
res = []
for model_name in self.pool:
diff --git a/addons/project_issue_sheet/project_issue_sheet_view.xml b/addons/project_issue_sheet/project_issue_sheet_view.xml
index 6d813b44239..39ff9ca0010 100644
--- a/addons/project_issue_sheet/project_issue_sheet_view.xml
+++ b/addons/project_issue_sheet/project_issue_sheet_view.xml
@@ -32,6 +32,7 @@
<field invisible="1" name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)"/>
<field invisible="1" name="amount"/>
<field invisible="1" name="general_account_id"/>
+ <field invisible="1" name="to_invoice"/>
</tree>
</field>
</page>
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 0aaa1362290..25d67dd1df1 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -1922,7 +1922,6 @@ class stock_move(osv.osv):
result = {
'product_uom_qty': 0.00
}
- warning = {}
if (not product_id) or (product_uos_qty <= 0.0):
result['product_uos_qty'] = 0.0
@@ -1931,21 +1930,14 @@ class stock_move(osv.osv):
product_obj = self.pool.get('product.product')
uos_coeff = product_obj.read(cr, uid, product_id, ['uos_coeff'])
- # Warn if the quantity was decreased
- for move in self.read(cr, uid, ids, ['product_uos_qty']):
- if product_uos_qty < move['product_uos_qty']:
- warning.update({
- 'title': _('Warning: No Back Order'),
- 'message': _("By changing the quantity here, you accept the "
- "new quantity as complete: OpenERP will not "
- "automatically generate a Back Order.")})
- break
+ # No warning if the quantity was decreased to avoid double warnings:
+ # The clients should call onchange_quantity too anyway
if product_uos and product_uom and (product_uom != product_uos):
result['product_uom_qty'] = product_uos_qty / uos_coeff['uos_coeff']
else:
result['product_uom_qty'] = product_uos_qty
- return {'value': result, 'warning': warning}
+ return {'value': result}
def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False, loc_dest_id=False, partner_id=False):
""" On change of product id, if finds UoM, UoS, quantity and UoS quantity.
diff --git a/addons/survey/survey.py b/addons/survey/survey.py
index 590d7ae22c8..1389e63e9e2 100644
--- a/addons/survey/survey.py
+++ b/addons/survey/survey.py
@@ -360,7 +360,7 @@ class survey_survey(osv.Model):
for cell in product(rows.keys(), answers.keys()):
res[cell] = 0
for input_line in question.user_input_line_ids:
- if input_line.answer_type == 'suggestion' and not(current_filters) or input_line.user_input_id.id in current_filters:
+ if input_line.answer_type == 'suggestion' and (not(current_filters) or input_line.user_input_id.id in current_filters):
res[(input_line.value_suggested_row.id, input_line.value_suggested.id)] += 1
result_summary = {'answers': answers, 'rows': rows, 'result': res}
@@ -993,6 +993,8 @@ class survey_user_input_line(osv.Model):
def __get_mark(self, cr, uid, value_suggested, context=None):
try:
mark = self.pool.get('survey.label').browse(cr, uid, int(value_suggested), context=context).quizz_mark
+ except AttributeError:
+ mark = 0.0
except KeyError:
mark = 0.0
except ValueError:
@@ -1140,7 +1142,7 @@ class survey_user_input_line(osv.Model):
comment_answer = post.pop(("%s_%s" % (answer_tag, 'comment')), '').strip()
if comment_answer:
- vals.update({'answer_type': 'text', 'value_text': comment_answer})
+ vals.update({'answer_type': 'text', 'value_text': comment_answer, 'skipped': False})
self.create(cr, uid, vals, context=context)
return True
diff --git a/addons/web_linkedin/web_linkedin.py b/addons/web_linkedin/web_linkedin.py
index 83132511a17..a0919f7968e 100644
--- a/addons/web_linkedin/web_linkedin.py
+++ b/addons/web_linkedin/web_linkedin.py
@@ -34,7 +34,7 @@ class Binary(openerp.http.Controller):
_scheme, _netloc, path, params, query, fragment = urlparse(url)
# media.linkedin.com is the master domain for LinkedIn media (replicated to CDNs),
# so forcing it should always work and prevents abusing this method to load arbitrary URLs
- url = urlunparse(('http', 'media.linkedin.com', path, params, query, fragment))
+ url = urlunparse(('http', 'media.licdn.com', path, params, query, fragment))
bfile = urllib2.urlopen(url)
return base64.b64encode(bfile.read())
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index f3bb906d4ba..2153e293240 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -10,7 +10,7 @@ import werkzeug.routing
import openerp
from openerp.addons.base import ir
from openerp.addons.base.ir import ir_qweb
-from openerp.addons.website.models.website import slug, url_for
+from openerp.addons.website.models.website import slug, url_for, _UNSLUG_RE
from openerp.http import request
from openerp.osv import orm
@@ -209,7 +209,7 @@ class ModelConverter(ir.ir_http.ModelConverter):
def __init__(self, url_map, model=False, domain='[]'):
super(ModelConverter, self).__init__(url_map, model)
self.domain = domain
- self.regex = r'(?:[A-Za-z0-9-_]+?-)?(\d+)(?=$|/)'
+ self.regex = _UNSLUG_RE.pattern
def to_url(self, value):
return slug(value)
@@ -218,7 +218,7 @@ class ModelConverter(ir.ir_http.ModelConverter):
m = re.match(self.regex, value)
_uid = RequestUID(value=value, match=m, converter=self)
return request.registry[self.model].browse(
- request.cr, _uid, int(m.group(1)), context=request.context)
+ request.cr, _uid, int(m.group(2)), context=request.context)
def generate(self, cr, uid, query=None, args=None, context=None):
obj = request.registry[self.model]
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 4cda81c7448..5921e6cfca4 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -102,11 +102,23 @@ def slug(value):
else:
# assume name_search result tuple
id, name = value
- slugname = slugify(name or '')
+ slugname = slugify(name or '').strip().strip('-')
if not slugname:
return str(id)
return "%s-%d" % (slugname, id)
+
+_UNSLUG_RE = re.compile(r'(?:(\w{1,2}|\w[a-zA-Z0-9-_]+?\w)-)?(-?\d+)(?=$|/)')
+
+def unslug(s):
+ """Extract slug and id from a string.
+ Always return un 2-tuple (str|None, int|None)
+ """
+ m = _UNSLUG_RE.match(s)
+ if not m:
+ return None, None
+ return m.group(1), int(m.group(2))
+
def urlplus(url, params):
return werkzeug.Href(url)(params or None)
@@ -237,7 +249,7 @@ class website(osv.osv):
# Compute Pager
page_count = int(math.ceil(float(total) / step))
- page = max(1, min(int(page), page_count))
+ page = max(1, min(int(page if str(page).isdigit() else 1), page_count))
scope -= 1
pmin = max(page - int(math.floor(scope/2)), 1)
diff --git a/addons/website/tests/test_converter.py b/addons/website/tests/test_converter.py
index ca72a361ac2..6a6b046ca93 100644
--- a/addons/website/tests/test_converter.py
+++ b/addons/website/tests/test_converter.py
@@ -9,10 +9,32 @@ from lxml.builder import E
from openerp.tests import common
from openerp.addons.base.ir import ir_qweb
from openerp.addons.website.models.ir_qweb import html_to_text
+from openerp.addons.website.models.website import unslug
impl = getDOMImplementation()
document = impl.createDocument(None, None, None)
+class TestUnslug(unittest2.TestCase):
+ def test_unslug(self):
+ tests = {
+ '': (None, None),
+ 'foo': (None, None),
+ 'foo-': (None, None),
+ '-': (None, None),
+ 'foo-1': ('foo', 1),
+ 'foo-bar-1': ('foo-bar', 1),
+ 'foo--1': ('foo', -1),
+ '1': (None, 1),
+ '1-1': ('1', 1),
+ '--1': (None, None),
+ 'foo---1': (None, None),
+ 'foo1': (None, None),
+ }
+
+ for slug, expected in tests.iteritems():
+ self.assertEqual(unslug(slug), expected)
+
+
class TestHTMLToText(unittest2.TestCase):
def test_rawstring(self):
self.assertEqual(
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index c23e18ebf8e..d0c4231eac6 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -426,7 +426,7 @@
<table class="table js_kanban">
<thead>
<tr>
- <t t-set="width" t-value="str(round(100.0 / len(objects), 2)) + '%'"/>
+ <t t-set="width" t-value="str(round(100.0 / (len(objects) if objects else 1), 2)) + '%'"/>
<t t-foreach="objects">
<th t-att-width="width">
<div t-field="column_id.name" class="text-center"></div>
diff --git a/addons/website_crm/controllers/main.py b/addons/website_crm/controllers/main.py
index 5f6853b391d..37d661e8a04 100644
--- a/addons/website_crm/controllers/main.py
+++ b/addons/website_crm/controllers/main.py
@@ -52,6 +52,8 @@ class contactus(http.Controller):
elif field_name not in _TECHNICAL: # allow to add some free fields or blacklisted field like ID
post_description.append("%s: %s" % (field_name, field_value))
+ if "name" not in kwargs and values.get("contact_name"): # if kwarg.name is empty, it's an error, we cannot copy the contact_name
+ values["name"] = values.get("contact_name")
# fields validation : Check that required field from model crm_lead exists
error = set(field for field in _REQUIRED if not kwargs.get(field))
diff --git a/addons/website_crm_partner_assign/controllers/main.py b/addons/website_crm_partner_assign/controllers/main.py
index c23bddc5ea2..ea0ec1506ba 100644
--- a/addons/website_crm_partner_assign/controllers/main.py
+++ b/addons/website_crm_partner_assign/controllers/main.py
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
import logging
-import re
import werkzeug
_logger = logging.getLogger(__name__)
@@ -13,7 +12,7 @@ except ImportError:
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
-from openerp.addons.website.models.website import slug
+from openerp.addons.website.models.website import slug, unslug
from openerp.tools.translate import _
@@ -146,7 +145,7 @@ class WebsiteCrmPartnerAssign(http.Controller):
# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/partners/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, partner_name='', **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
+ _, partner_id = unslug(partner_id)
current_grade, current_country = None, None
grade_id = post.get('grade_id')
country_id = post.get('country_id')
@@ -158,8 +157,7 @@ class WebsiteCrmPartnerAssign(http.Controller):
country_ids = request.registry['res.country'].exists(request.cr, request.uid, int(country_id), context=request.context)
if country_ids:
current_country = request.registry['res.country'].browse(request.cr, request.uid, country_ids[0], context=request.context)
- if mo:
- partner_id = int(mo.group(1))
+ if partner_id:
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
if partner.exists() and partner.website_published:
values = {
diff --git a/addons/website_customer/controllers/main.py b/addons/website_customer/controllers/main.py
index 3e396f23fcf..fcb2d0d8ded 100644
--- a/addons/website_customer/controllers/main.py
+++ b/addons/website_customer/controllers/main.py
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
-import re
-
import openerp
from openerp import SUPERUSER_ID
from openerp.addons.web import http
+from openerp.addons.website.models.website import unslug
from openerp.tools.translate import _
from openerp.addons.web.http import request
import werkzeug.urls
@@ -84,9 +83,8 @@ class WebsiteCustomer(http.Controller):
# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/customers/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
- if mo:
- partner_id = int(mo.group(1))
+ _, partner_id = unslug(partner_id)
+ if partner_id:
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
if partner.exists() and partner.website_published:
values = {}
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index 16a6bd24edf..71432404f3a 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -25,6 +25,7 @@ from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import werkzeug.urls
+from werkzeug.exceptions import NotFound
from openerp import SUPERUSER_ID
from openerp import http
@@ -175,6 +176,16 @@ class website_event(http.Controller):
'event': event,
'main_object': event
}
+
+ if '.' not in page:
+ page = 'website_event.%s' % page
+
+ try:
+ request.website.get_template(page)
+ except ValueError, e:
+ # page not found
+ raise NotFound
+
return request.website.render(page, values)
@http.route(['/event/<model("event.event"):event>'], type='http', auth="public", website=True)
diff --git a/addons/website_membership/controllers/main.py b/addons/website_membership/controllers/main.py
index f4eb4bc46b6..73c894ac46f 100644
--- a/addons/website_membership/controllers/main.py
+++ b/addons/website_membership/controllers/main.py
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
-import re
-
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
+from openerp.addons.website.models.website import unslug
from openerp.tools.translate import _
import werkzeug.urls
@@ -105,9 +104,8 @@ class WebsiteMembership(http.Controller):
# Do not use semantic controller due to SUPERUSER_ID
@http.route(['/members/<partner_id>'], type='http', auth="public", website=True)
def partners_detail(self, partner_id, **post):
- mo = re.search('-([-0-9]+)$', str(partner_id))
- if mo:
- partner_id = int(mo.group(1))
+ _, partner_id = unslug(partner_id)
+ if partner_id:
partner = request.registry['res.partner'].browse(request.cr, SUPERUSER_ID, partner_id, context=request.context)
if partner.exists() and partner.website_published:
values = {}
diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py
index c7af837aff1..7d6b92ad315 100644
--- a/openerp/addons/base/res/res_partner.py
+++ b/openerp/addons/base/res/res_partner.py
@@ -592,7 +592,7 @@ class res_partner(osv.osv, format_address):
""" Supported syntax:
- 'Raoul <raoul@grosbedon.fr>': will find name and email address
- otherwise: default, everything is set as the name """
- emails = tools.email_split(text)
+ emails = tools.email_split(text.replace(' ',','))
if emails:
email = emails[0]
name = text[:text.index(email)].replace('"', '').replace('<', '').strip()
diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml
index 50045aaf270..e658ddc0fe7 100644
--- a/openerp/addons/base/res/res_partner_view.xml
+++ b/openerp/addons/base/res/res_partner_view.xml
@@ -159,8 +159,8 @@
<div class="oe_edit_only">
<field name="use_parent_address" class="oe_inline"
on_change="onchange_address(use_parent_address, parent_id)"
- attrs="{'invisible': [('parent_id','=', False),('use_parent_address','=',False)]}"/>
- <label for="use_parent_address" attrs="{'invisible': [('parent_id','=', False),('use_parent_address','=',False)]}"/>
+ attrs="{'invisible': ['|', ('is_company', '=', True),('parent_id', '=', False)]}"/>
+ <label for="use_parent_address" attrs="{'invisible': ['|', ('is_company', '=', True), ('parent_id', '=', False)]}"/>
</div>
<button name="open_parent" type="object" string="(edit company address)" class="oe_link oe_edit_only"
attrs="{'invisible': ['|',('parent_id','=', False),('use_parent_address','=',False)]}"/>
diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py
index af046836192..dde2315aa24 100644
--- a/openerp/report/render/rml2pdf/trml2pdf.py
+++ b/openerp/report/render/rml2pdf/trml2pdf.py
@@ -379,7 +379,11 @@ class _rml_canvas(object):
v = utils.attr_get(node, ['x','y'])
text=self._textual(node, **v)
text = utils.xml2str(text)
- self.canvas.drawString(text=text, **v)
+ try:
+ self.canvas.drawString(text=text, **v)
+ except TypeError:
+ _logger.error("Bad RML: <drawString> tag requires attributes 'x' and 'y'!")
+ raise
def _drawCenteredString(self, node):
v = utils.attr_get(node, ['x','y'])
@@ -1005,10 +1009,10 @@ class _rml_template(object):
story_cnt = 0
for node_story in node_stories:
if story_cnt > 0:
+ # Reset Page Number with new story tag
+ fis.append(PageReset())
fis.append(platypus.PageBreak())
fis += r.render(node_story)
- # Reset Page Number with new story tag
- fis.append(PageReset())
story_cnt += 1
try:
if self.localcontext and self.localcontext.get('internal_header',False):