Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions addons/account/tests/test_fiscal_position.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import logging
from odoo.tests import common


_logger = logging.getLogger(__name__)


class TestFiscalPosition(common.TransactionCase):
"""Tests for fiscal positions in auto apply (account.fiscal.position).
If a partner has a vat number, the fiscal positions with "vat_required=True"
Expand Down Expand Up @@ -62,10 +67,21 @@ def setUp(self):

def test_10_fp_country(self):
def assert_fp(partner, expected_pos, message):
self.assertEquals(
self.fp.get_fiscal_position(partner.id),
expected_pos.id,
message)
partner_pos_id = self.fp.get_fiscal_position(partner.id)
# If we know assert will raise an error, tell names of
# actual fiscal positions:
if partner_pos_id != expected_pos.id:
partner_pos = self.fp.browse([partner_pos_id])
_logger.error(
"Partner %s in country %s and state %s with zip %s"
" has fp %s, but expected fp is %s",
partner.name,
partner.country_id.name,
partner.state_id.name,
partner.zip,
partner_pos.name,
expected_pos.name)
self.assertEquals(partner_pos_id, expected_pos.id, message)

george, jc, ben, alberto = self.george, self.jc, self.ben, self.alberto

Expand Down Expand Up @@ -120,10 +136,17 @@ def assert_fp(partner, expected_pos, message):
assert_fp(george, self.fr_b2b_zip100, "FR-B2B with zip range should have precedence")

# States
self.fr_b2b_state = self.fr_b2b.copy(dict(state_ids=[(4, self.state_fr.id)], sequence=70))
self.fr_b2b_state = self.fr_b2b.copy(dict(
state_ids=[(4, self.state_fr.id)],
name="EU-VAT-FR-B2B-state",
sequence=70))
george.state_id = self.state_fr
self.assertEquals(
george.state_id, self.state_fr, "Setting state failed")
assert_fp(george, self.fr_b2b_zip100, "FR-B2B with zip should have precedence over states")
george.zip = 0
self.assertEquals(
george.state_id, self.state_fr, "State has been reset somehow")
assert_fp(george, self.fr_b2b_state, "FR-B2B with states should have precedence")

# Dedicated position has max precedence
Expand Down
39 changes: 37 additions & 2 deletions odoo/addons/base/ir/ir_ui_menu.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import base64
import logging
import operator
import re

from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
from odoo.exceptions import ValidationError, MissingError
from odoo.http import request
from odoo.modules import get_module_resource
from odoo.tools.safe_eval import safe_eval
Expand All @@ -15,6 +15,9 @@
NUMBER_PARENS = re.compile(r"\(([0-9]+)\)")


_logger = logging.getLogger(__name__) # pylint: disable=invalid-name


class IrUiMenu(models.Model):
_name = 'ir.ui.menu'
_order = "sequence,id"
Expand Down Expand Up @@ -264,6 +267,10 @@ def load_menus(self, debug):
:return: the menu root
:rtype: dict('children': menu_nodes)
"""
if not tools.config['test_enable']:
# as tests can run during initialization of the database, we
# can't do our check here because the menu isn't initialized yet
self._check_menu_corruption()
fields = ['name', 'sequence', 'parent_id', 'action', 'web_icon', 'web_icon_data']
menu_roots = self.get_user_roots()
menu_roots_data = menu_roots.read(fields) if menu_roots else []
Expand Down Expand Up @@ -301,3 +308,31 @@ def load_menus(self, debug):
menu_item.setdefault('children', []).sort(key=operator.itemgetter('sequence'))

return menu_root

def _check_menu_corruption(self):
"""Raise error when menu hierarchy has become corrupted."""
# pylint: disable=invalid-name
STATEMENT = \
"SELECT COUNT(*) FROM ir_ui_menu" \
" WHERE NOT parent_id IS NULL" \
" AND (parent_left is null or parent_right is null)"
self.env.cr.execute(STATEMENT)
count = self.env.cr.fetchone()[0]
if count > 0:
STATEMENT_EXTENDED = \
"SELECT mn.id, mn.parent_id, mn.name, dt.name, dt.module" \
" FROM ir_ui_menu mn" \
" LEFT OUTER JOIN ir_model_data dt" \
" ON dt.model = 'ir.ui.menu' AND dt.res_id = mn.id" \
" WHERE NOT parent_id IS NULL" \
" AND (parent_left is null or parent_right is null)"
self.env.cr.execute(STATEMENT_EXTENDED)
for record in self.env.cr.fetchall():
_logger.error(
"Menu %s with id %d and parent_id %d is missing link"
" to parent_left and/or parent_right.\n"
"Menu added from %s.%s.",
record[2], record[0], record[1],
record[4] or '?', record[3] or '?')
raise MissingError(
"Menu's have been corrupted. Regenerate parent hierarchy.")
21 changes: 15 additions & 6 deletions odoo/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
]

import logging
import traceback
from collections import defaultdict, Mapping
from contextlib import contextmanager
from inspect import currentframe, getargspec
Expand Down Expand Up @@ -673,12 +674,20 @@ def call_kw_model(method, self, args, kwargs):
return downgrade(method, result, recs, args, kwargs)

def call_kw_multi(method, self, args, kwargs):
ids, args = args[0], args[1:]
context, args, kwargs = split_context(method, args, kwargs)
recs = self.with_context(context or {}).browse(ids)
_logger.debug("call %s.%s(%s)", recs, method.__name__, Params(args, kwargs))
result = method(recs, *args, **kwargs)
return downgrade(method, result, recs, args, kwargs)
try:
ids, args = args[0], args[1:]
context, args, kwargs = split_context(method, args, kwargs)
recs = self.with_context(context or {}).browse(ids)
_logger.debug("call %s.%s(%s)", recs, method.__name__, Params(args, kwargs))
result = method(recs, *args, **kwargs)
return downgrade(method, result, recs, args, kwargs)
except:
_logger.error(traceback.format_exc())
_logger.error(
"Unexpected error calling %s, on %s with args=%s and kwargs=%s." %
(method, self, args, kwargs)
)
raise

def call_kw(model, name, args, kwargs):
""" Invoke the given method ``name`` on the recordset ``model``. """
Expand Down
14 changes: 11 additions & 3 deletions odoo/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,9 +541,17 @@ def _setup_related_full(self, model):
# determine the chain of fields, and make sure they are all set up
target = model
for name in self.related:
field = target._fields[name]
field.setup_full(target)
target = target[name]
try:
field = target._fields[name]
field.setup_full(target)
target = target[name]
except:
_logger.error(
"Problem setting up related field %s for model %s" %
(name, self.model_name)
)
raise


self.related_field = field

Expand Down
9 changes: 8 additions & 1 deletion odoo/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,14 @@ def load_addons(self):
manifest['addons_path'] = addons_path
_logger.debug("Loading %s", module)
if 'odoo.addons' in sys.modules:
m = __import__('odoo.addons.' + module)
try:
m = __import__('odoo.addons.' + module)
except:
_logger.error(traceback.format_exc())
_logger.error(
"Could not load module %s" % module
)
m = None
else:
m = None
addons_module[module] = m
Expand Down
3 changes: 3 additions & 0 deletions odoo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3569,6 +3569,7 @@ def write(self, vals):

if unknown:
_logger.warning("%s.write() with unknown fields: %s", self._name, ', '.join(sorted(unknown)))
_logger.info("Unknown fields: %s", str(vals))

protected_fields = map(self._fields.get, new_vals)
with self.env.protecting(protected_fields, self):
Expand Down Expand Up @@ -3741,6 +3742,7 @@ def _write(self, vals):

if unknown_fields:
_logger.warning('No such field(s) in model %s: %s.', self._name, ', '.join(unknown_fields))
_logger.info("Unknown fields: %s", str(vals))

# check Python constraints
self._validate_fields(vals)
Expand Down Expand Up @@ -3856,6 +3858,7 @@ def create(self, vals):

if unknown:
_logger.warning("%s.create() includes unknown fields: %s", self._name, ', '.join(sorted(unknown)))
_logger.info("Unknown fields: %s", str(vals))

# create record with old-style fields
record = self.browse(self._create(old_vals))
Expand Down
8 changes: 7 additions & 1 deletion odoo/modules/loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,13 @@ def _load_data(cr, module_name, idref, mode, kind):
if pre_init:
getattr(py_module, pre_init)(cr)

model_names = registry.load(cr, package)
try:
model_names = registry.load(cr, package)
except:
_logger.error(
"Error loading module %s" % package
)
raise

loaded_modules.append(package.name)
if needs_update:
Expand Down
24 changes: 22 additions & 2 deletions odoo/modules/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,21 @@ def load(self, cr, module):
model_names = []
for cls in models.MetaModel.module_to_models.get(module.name, []):
# models register themselves in self.models
model = cls._build_model(self, cr)
try:
model = cls._build_model(self, cr)
except:
# determine name for model to give clear error message:
# (code adapted from what is done in _build_model method)
parents = getattr(cls, '_inherit', [])
parents = [parents] if isinstance(parents, basestring) \
else (parents or [])
model_name = (
cls._name or
(len(parents) == 1 and parents[0]) or
cls.__name__
)
_logger.error("Error building model %s" % model_name)
raise
model_names.append(model._name)

return self.descendants(model_names, '_inherit', '_inherits')
Expand Down Expand Up @@ -297,7 +311,13 @@ def setup_models(self, cr, partial=False):
model._setup_base(partial)

for model in models:
model._setup_fields(partial)
try:
model._setup_fields(partial)
except:
_logger.error(
"Error setting up fields for model %s" % model._name
)
raise

for model in models:
model._setup_complete()
Expand Down
2 changes: 2 additions & 0 deletions odoo/osv/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,8 @@ def to_sql(self):
q2 = stack.pop()
stack.append('(%s %s %s)' % (q1, ops[leaf.leaf], q2,))

if len(stack) <> 1:
_logger.error("Stack is now %s" % stack)
assert len(stack) == 1
query = stack[0]
joins = ' AND '.join(self.joins)
Expand Down