[IMP] base: replace 'sql_constraint' translations by 'model' translations
Store the SQL constraint message directly in the field `message` of the corresponding `ir.model.constraint` record, and manage translations from there. Those records are given an XML id in order to be tracked in PO files. The translation type 'sql_constraint` is removed.
This commit is contained in:
@@ -970,6 +970,7 @@ class IrModelConstraint(models.Model):
|
|||||||
name = fields.Char(string='Constraint', required=True, index=True,
|
name = fields.Char(string='Constraint', required=True, index=True,
|
||||||
help="PostgreSQL constraint or foreign key name.")
|
help="PostgreSQL constraint or foreign key name.")
|
||||||
definition = fields.Char(help="PostgreSQL constraint definition")
|
definition = fields.Char(help="PostgreSQL constraint definition")
|
||||||
|
message = fields.Char(help="Error message returned when the constraint is violated.", translate=True)
|
||||||
model = fields.Many2one('ir.model', required=True, ondelete="cascade", index=True)
|
model = fields.Many2one('ir.model', required=True, ondelete="cascade", index=True)
|
||||||
module = fields.Many2one('ir.module.module', required=True, index=True)
|
module = fields.Many2one('ir.module.module', required=True, index=True)
|
||||||
type = fields.Char(string='Constraint Type', required=True, size=1, index=True,
|
type = fields.Char(string='Constraint Type', required=True, size=1, index=True,
|
||||||
@@ -1033,9 +1034,10 @@ class IrModelConstraint(models.Model):
|
|||||||
default['name'] = self.name + '_copy'
|
default['name'] = self.name + '_copy'
|
||||||
return super(IrModelConstraint, self).copy(default)
|
return super(IrModelConstraint, self).copy(default)
|
||||||
|
|
||||||
def _reflect_constraint(self, model, conname, type, definition, module):
|
def _reflect_constraint(self, model, conname, type, definition, module, message=None):
|
||||||
""" Reflect the given constraint, to make it possible to delete it later
|
""" Reflect the given constraint, and return its corresponding record.
|
||||||
when the module is uninstalled. ``type`` is either 'f' or 'u'
|
The reflection makes it possible to remove a constraint when its
|
||||||
|
corresponding module is uninstalled. ``type`` is either 'f' or 'u'
|
||||||
depending on the constraint being a foreign key or not.
|
depending on the constraint being a foreign key or not.
|
||||||
"""
|
"""
|
||||||
if not module:
|
if not module:
|
||||||
@@ -1044,23 +1046,28 @@ class IrModelConstraint(models.Model):
|
|||||||
return
|
return
|
||||||
assert type in ('f', 'u')
|
assert type in ('f', 'u')
|
||||||
cr = self._cr
|
cr = self._cr
|
||||||
query = """ SELECT type, definition
|
query = """ SELECT c.id, type, definition, message
|
||||||
FROM ir_model_constraint c, ir_module_module m
|
FROM ir_model_constraint c, ir_module_module m
|
||||||
WHERE c.module=m.id AND c.name=%s AND m.name=%s """
|
WHERE c.module=m.id AND c.name=%s AND m.name=%s """
|
||||||
cr.execute(query, (conname, module))
|
cr.execute(query, (conname, module))
|
||||||
cons = cr.dictfetchone()
|
cons = cr.dictfetchone()
|
||||||
if not cons:
|
if not cons:
|
||||||
query = """ INSERT INTO ir_model_constraint
|
query = """ INSERT INTO ir_model_constraint
|
||||||
(name, date_init, date_update, module, model, type, definition)
|
(name, date_init, date_update, module, model, type, definition, message)
|
||||||
VALUES (%s, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC',
|
VALUES (%s, now() AT TIME ZONE 'UTC', now() AT TIME ZONE 'UTC',
|
||||||
(SELECT id FROM ir_module_module WHERE name=%s),
|
(SELECT id FROM ir_module_module WHERE name=%s),
|
||||||
(SELECT id FROM ir_model WHERE model=%s), %s, %s) """
|
(SELECT id FROM ir_model WHERE model=%s), %s, %s, %s)
|
||||||
cr.execute(query, (conname, module, model._name, type, definition))
|
RETURNING id"""
|
||||||
elif cons['type'] != type or (definition and cons['definition'] != definition):
|
cr.execute(query, (conname, module, model._name, type, definition, message))
|
||||||
|
return self.browse(cr.fetchone()[0])
|
||||||
|
|
||||||
|
cons_id = cons.pop('id')
|
||||||
|
if cons != dict(type=type, definition=definition, message=message):
|
||||||
query = """ UPDATE ir_model_constraint
|
query = """ UPDATE ir_model_constraint
|
||||||
SET date_update=now() AT TIME ZONE 'UTC', type=%s, definition=%s
|
SET date_update=now() AT TIME ZONE 'UTC', type=%s, definition=%s, message=%s
|
||||||
WHERE name=%s AND module=(SELECT id FROM ir_module_module WHERE name=%s) """
|
WHERE id=%s"""
|
||||||
cr.execute(query, (type, definition, conname, module))
|
cr.execute(query, (type, definition, message, cons_id))
|
||||||
|
return self.browse(cons_id)
|
||||||
|
|
||||||
def _reflect_model(self, model):
|
def _reflect_model(self, model):
|
||||||
""" Reflect the _sql_constraints of the given model. """
|
""" Reflect the _sql_constraints of the given model. """
|
||||||
@@ -1075,10 +1082,16 @@ class IrModelConstraint(models.Model):
|
|||||||
for constraint in getattr(cls, '_local_sql_constraints', ())
|
for constraint in getattr(cls, '_local_sql_constraints', ())
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, definition, _) in model._sql_constraints:
|
data_list = []
|
||||||
|
for (key, definition, message) in model._sql_constraints:
|
||||||
conname = '%s_%s' % (model._table, key)
|
conname = '%s_%s' % (model._table, key)
|
||||||
module = constraint_module.get(key)
|
module = constraint_module.get(key)
|
||||||
self._reflect_constraint(model, conname, 'u', cons_text(definition), module)
|
record = self._reflect_constraint(model, conname, 'u', cons_text(definition), module, message)
|
||||||
|
if record:
|
||||||
|
xml_id = '%s.constraint_%s' % (module, conname)
|
||||||
|
data_list.append(dict(xml_id=xml_id, record=record))
|
||||||
|
|
||||||
|
self.env['ir.model.data']._update_xmlids(data_list)
|
||||||
|
|
||||||
|
|
||||||
class IrModelRelation(models.Model):
|
class IrModelRelation(models.Model):
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ TRANSLATION_TYPE = [
|
|||||||
('selection', 'Selection'),
|
('selection', 'Selection'),
|
||||||
('code', 'Code'),
|
('code', 'Code'),
|
||||||
('constraint', 'Constraint'),
|
('constraint', 'Constraint'),
|
||||||
('sql_constraint', 'SQL Constraint')
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -127,9 +126,9 @@ class IrTranslationImport(object):
|
|||||||
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
|
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
|
||||||
SELECT name, lang, res_id, src, type, value, module, state, comments
|
SELECT name, lang, res_id, src, type, value, module, state, comments
|
||||||
FROM %s
|
FROM %s
|
||||||
WHERE type IN ('selection', 'constraint', 'sql_constraint')
|
WHERE type IN ('selection', 'constraint')
|
||||||
AND noupdate IS NOT TRUE
|
AND noupdate IS NOT TRUE
|
||||||
ON CONFLICT (type, lang, name, md5(src)) WHERE type IN ('selection', 'constraint', 'sql_constraint')
|
ON CONFLICT (type, lang, name, md5(src)) WHERE type IN ('selection', 'constraint')
|
||||||
DO UPDATE SET (name, lang, res_id, src, type, value, module, state, comments) = (EXCLUDED.name, EXCLUDED.lang, EXCLUDED.res_id, EXCLUDED.src, EXCLUDED.type, EXCLUDED.value, EXCLUDED.module, EXCLUDED.state, EXCLUDED.comments)
|
DO UPDATE SET (name, lang, res_id, src, type, value, module, state, comments) = (EXCLUDED.name, EXCLUDED.lang, EXCLUDED.res_id, EXCLUDED.src, EXCLUDED.type, EXCLUDED.value, EXCLUDED.module, EXCLUDED.state, EXCLUDED.comments)
|
||||||
WHERE EXCLUDED.value IS NOT NULL AND EXCLUDED.value != '';
|
WHERE EXCLUDED.value IS NOT NULL AND EXCLUDED.value != '';
|
||||||
""" % (self._model_table, self._table))
|
""" % (self._model_table, self._table))
|
||||||
@@ -259,7 +258,7 @@ class IrTranslation(models.Model):
|
|||||||
if not tools.index_exists(self._cr, 'ir_translation_model_unique'):
|
if not tools.index_exists(self._cr, 'ir_translation_model_unique'):
|
||||||
self._cr.execute("CREATE UNIQUE INDEX ir_translation_model_unique ON ir_translation (type, lang, name, res_id) WHERE type = 'model'")
|
self._cr.execute("CREATE UNIQUE INDEX ir_translation_model_unique ON ir_translation (type, lang, name, res_id) WHERE type = 'model'")
|
||||||
if not tools.index_exists(self._cr, 'ir_translation_selection_unique'):
|
if not tools.index_exists(self._cr, 'ir_translation_selection_unique'):
|
||||||
self._cr.execute("CREATE UNIQUE INDEX ir_translation_selection_unique ON ir_translation (type, lang, name, md5(src)) WHERE type IN ('selection', 'constraint', 'sql_constraint')")
|
self._cr.execute("CREATE UNIQUE INDEX ir_translation_selection_unique ON ir_translation (type, lang, name, md5(src)) WHERE type IN ('selection', 'constraint')")
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -468,6 +468,9 @@
|
|||||||
<field name="date_update" />
|
<field name="date_update" />
|
||||||
<field name="date_init" />
|
<field name="date_init" />
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="message"/>
|
||||||
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_tests" name="Test New Api Assets Tests" inherit_id="web.assets_tests">
|
<template id="assets_tests" name="Test New Api Assets Tests" inherit_id="web.assets_tests">
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/test_new_api/static/tests/tours/constraint.js"></script>
|
||||||
<script type="text/javascript" src="/test_new_api/static/tests/tours/x2many.js"></script>
|
<script type="text/javascript" src="/test_new_api/static/tests/tours/x2many.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * test_new_api
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 13.0alpha1\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2019-07-08 06:43+0000\n"
|
||||||
|
"PO-Revision-Date: 2019-07-08 06:43+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: test_new_api
|
||||||
|
#: model:ir.model.constraint,message:test_new_api.constraint_test_new_api_category_positive_color
|
||||||
|
msgid "The color code must be positive !"
|
||||||
|
msgstr "La couleur doit être une valeur positive !"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * test_new_api
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 13.0alpha1\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2019-07-08 06:43+0000\n"
|
||||||
|
"PO-Revision-Date: 2019-07-08 06:43+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: test_new_api
|
||||||
|
#: model:ir.model.constraint,message:test_new_api.constraint_test_new_api_category_positive_color
|
||||||
|
msgid "The color code must be positive !"
|
||||||
|
msgstr ""
|
||||||
@@ -24,6 +24,10 @@ class Category(models.Model):
|
|||||||
discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category',
|
discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category',
|
||||||
'category', 'discussion')
|
'category', 'discussion')
|
||||||
|
|
||||||
|
_sql_constraints = [
|
||||||
|
('positive_color', 'CHECK(color >= 0)', 'The color code must be positive !')
|
||||||
|
]
|
||||||
|
|
||||||
@api.depends('name', 'parent.display_name') # this definition is recursive
|
@api.depends('name', 'parent.display_name') # this definition is recursive
|
||||||
def _compute_display_name(self):
|
def _compute_display_name(self):
|
||||||
for cat in self:
|
for cat in self:
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
odoo.define('web.test.constraint', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var tour = require("web_tour.tour");
|
||||||
|
var inc;
|
||||||
|
|
||||||
|
tour.register('sql_constaint', {
|
||||||
|
url: '/web?debug=1#action=test_new_api.action_categories',
|
||||||
|
test: true,
|
||||||
|
}, [
|
||||||
|
{
|
||||||
|
content: "wait web client",
|
||||||
|
trigger: '.breadcrumb:contains(Categories)',
|
||||||
|
}, { // create test category
|
||||||
|
content: "create new category",
|
||||||
|
trigger: 'button.o_list_button_add',
|
||||||
|
}, {
|
||||||
|
content: "insert content",
|
||||||
|
trigger: 'input.o_required_modifier',
|
||||||
|
run: 'text Test Category',
|
||||||
|
}, { // try to insert a value that will raise the SQL constraint
|
||||||
|
content: "insert invalid value",
|
||||||
|
trigger: 'input[name="color"]',
|
||||||
|
run: 'text -1',
|
||||||
|
}, { // save
|
||||||
|
content: "save category",
|
||||||
|
trigger: 'button.o_form_button_save',
|
||||||
|
}, { // check popup content
|
||||||
|
content: "check notification box",
|
||||||
|
trigger: '.o_notification_content:contains(The color code must be positive !)',
|
||||||
|
run: function () {}, // it's a check
|
||||||
|
}]);
|
||||||
|
});
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import odoo.tests
|
import odoo.tests
|
||||||
|
from odoo.tools import mute_logger
|
||||||
|
|
||||||
|
|
||||||
@odoo.tests.common.tagged('post_install', '-at_install')
|
@odoo.tests.common.tagged('post_install', '-at_install')
|
||||||
@@ -14,3 +15,21 @@ class TestUi(odoo.tests.HttpCase):
|
|||||||
# too small or there are too many items preceding it in the tests menu
|
# too small or there are too many items preceding it in the tests menu
|
||||||
self.start_tour("/web#action=test_new_api.action_discussions",
|
self.start_tour("/web#action=test_new_api.action_discussions",
|
||||||
'widget_x2many', step_delay=100, login="admin", timeout=120)
|
'widget_x2many', step_delay=100, login="admin", timeout=120)
|
||||||
|
|
||||||
|
|
||||||
|
class TestUiTranslation(odoo.tests.HttpCase):
|
||||||
|
|
||||||
|
@mute_logger('odoo.sql_db', 'odoo.http')
|
||||||
|
def test_01_sql_constraints(self):
|
||||||
|
# Raise an SQL constraint and test the message
|
||||||
|
self.env['ir.translation']._load_module_terms(['test_new_api'], ['fr_FR'])
|
||||||
|
constraint = self.env.ref('test_new_api.constraint_test_new_api_category_positive_color')
|
||||||
|
message = constraint.with_context(lang='fr_FR').message
|
||||||
|
self.assertEqual(message, "La couleur doit être une valeur positive !")
|
||||||
|
|
||||||
|
# TODO: make the test work with French translations. As the transaction
|
||||||
|
# is rollbacked at insert and a new cusor is opened, can not test that
|
||||||
|
# the message is translated (_load_module_terms is also) rollbacked.
|
||||||
|
# Test individually the external id and loading of translation.
|
||||||
|
self.start_tour("/web#action=test_new_api.action_categories",
|
||||||
|
'sql_constaint', login="admin")
|
||||||
|
|||||||
@@ -245,6 +245,7 @@
|
|||||||
<field name="parent"/>
|
<field name="parent"/>
|
||||||
<field name="root_categ"/>
|
<field name="root_categ"/>
|
||||||
<field name="dummy"/>
|
<field name="dummy"/>
|
||||||
|
<field name="color"/>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+3
-3
@@ -584,9 +584,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _init_constraints_onchanges(cls):
|
def _init_constraints_onchanges(cls):
|
||||||
# store sql constraint error messages
|
# store list of sql constraint qualified names
|
||||||
for (key, _, msg) in cls._sql_constraints:
|
for (key, _, _) in cls._sql_constraints:
|
||||||
cls.pool._sql_error[cls._table + '_' + key] = msg
|
cls.pool._sql_constraints.add(cls._table + '_' + key)
|
||||||
|
|
||||||
# reset properties memoized on cls
|
# reset properties memoized on cls
|
||||||
cls._constraint_methods = BaseModel._constraint_methods
|
cls._constraint_methods = BaseModel._constraint_methods
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class Registry(Mapping):
|
|||||||
|
|
||||||
def init(self, db_name):
|
def init(self, db_name):
|
||||||
self.models = {} # model name/model instance mapping
|
self.models = {} # model name/model instance mapping
|
||||||
self._sql_error = {}
|
self._sql_constraints = set()
|
||||||
self._init = True
|
self._init = True
|
||||||
self._assertion_report = assertion_report.assertion_report()
|
self._assertion_report = assertion_report.assertion_report()
|
||||||
self._fields_by_model = None
|
self._fields_by_model = None
|
||||||
|
|||||||
+10
-15
@@ -10,7 +10,7 @@ import time
|
|||||||
import odoo
|
import odoo
|
||||||
from odoo.exceptions import UserError, ValidationError, QWebException
|
from odoo.exceptions import UserError, ValidationError, QWebException
|
||||||
from odoo.models import check_method_name
|
from odoo.models import check_method_name
|
||||||
from odoo.tools.translate import translate
|
from odoo.tools.translate import translate, translate_sql_constraint
|
||||||
from odoo.tools.translate import _
|
from odoo.tools.translate import _
|
||||||
|
|
||||||
from . import security
|
from . import security
|
||||||
@@ -73,18 +73,13 @@ def check(f):
|
|||||||
|
|
||||||
# We open a *new* cursor here, one reason is that failed SQL
|
# We open a *new* cursor here, one reason is that failed SQL
|
||||||
# queries (as in IntegrityError) will invalidate the current one.
|
# queries (as in IntegrityError) will invalidate the current one.
|
||||||
cr = False
|
with odoo.sql_db.db_connect(dbname).cursor() as cr:
|
||||||
|
if ttype == 'sql_constraint':
|
||||||
try:
|
res = translate_sql_constraint(cr, key=key, lang=lang)
|
||||||
cr = odoo.sql_db.db_connect(dbname).cursor()
|
|
||||||
res = translate(cr, name=False, source_type=ttype,
|
|
||||||
lang=lang, source=src)
|
|
||||||
if res:
|
|
||||||
return res
|
|
||||||
else:
|
else:
|
||||||
return src
|
res = translate(cr, name=False, source_type=ttype,
|
||||||
finally:
|
lang=lang, source=src)
|
||||||
if cr: cr.close()
|
return res or src
|
||||||
|
|
||||||
def _(src):
|
def _(src):
|
||||||
return tr(src, 'code')
|
return tr(src, 'code')
|
||||||
@@ -114,9 +109,9 @@ def check(f):
|
|||||||
time.sleep(wait_time)
|
time.sleep(wait_time)
|
||||||
except IntegrityError as inst:
|
except IntegrityError as inst:
|
||||||
registry = odoo.registry(dbname)
|
registry = odoo.registry(dbname)
|
||||||
for key in registry._sql_error.keys():
|
key = inst.diag.constraint_name
|
||||||
if key in inst.pgerror:
|
if key in registry._sql_constraints:
|
||||||
raise ValidationError(tr(registry._sql_error[key], 'sql_constraint') or inst.pgerror)
|
raise ValidationError(tr(key, 'sql_constraint') or inst.pgerror)
|
||||||
if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):
|
if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):
|
||||||
msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set')
|
msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set')
|
||||||
_logger.debug("IntegrityError", exc_info=True)
|
_logger.debug("IntegrityError", exc_info=True)
|
||||||
|
|||||||
+23
-9
@@ -352,6 +352,21 @@ def translate(cr, name, source_type, lang, source=None):
|
|||||||
res = res_trans and res_trans[0] or False
|
res = res_trans and res_trans[0] or False
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def translate_sql_constraint(cr, key, lang):
|
||||||
|
cr.execute("""
|
||||||
|
SELECT COALESCE(t.value, c.message) as message
|
||||||
|
FROM ir_model_constraint c
|
||||||
|
LEFT JOIN
|
||||||
|
(SELECT res_id, value FROM ir_translation
|
||||||
|
WHERE type='model'
|
||||||
|
AND name='ir.model.constraint,message'
|
||||||
|
AND lang=%s
|
||||||
|
AND value!='') AS t
|
||||||
|
ON c.id=t.res_id
|
||||||
|
WHERE name=%s and type='u'
|
||||||
|
""", (lang, key))
|
||||||
|
return cr.fetchone()[0]
|
||||||
|
|
||||||
class GettextAlias(object):
|
class GettextAlias(object):
|
||||||
|
|
||||||
def _get_db(self):
|
def _get_db(self):
|
||||||
@@ -445,7 +460,7 @@ class GettextAlias(object):
|
|||||||
if cr:
|
if cr:
|
||||||
# Try to use ir.translation to benefit from global cache if possible
|
# Try to use ir.translation to benefit from global cache if possible
|
||||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||||
res = env['ir.translation']._get_source(None, ('code','sql_constraint'), lang, source)
|
res = env['ir.translation']._get_source(None, ('code',), lang, source)
|
||||||
else:
|
else:
|
||||||
_logger.debug('no context cursor detected, skipping translation for "%r"', source)
|
_logger.debug('no context cursor detected, skipping translation for "%r"', source)
|
||||||
else:
|
else:
|
||||||
@@ -594,6 +609,9 @@ class PoFileReader:
|
|||||||
match = re.match(r'(sql_constraint|constraint):([\w.]+)', occurrence)
|
match = re.match(r'(sql_constraint|constraint):([\w.]+)', occurrence)
|
||||||
if match:
|
if match:
|
||||||
type, model = match.groups()
|
type, model = match.groups()
|
||||||
|
if type == "sql_constraint":
|
||||||
|
_logger.info("Skipped deprecated occurrence %s", occurrence)
|
||||||
|
continue
|
||||||
yield {
|
yield {
|
||||||
'type': type,
|
'type': type,
|
||||||
'name': model,
|
'name': model,
|
||||||
@@ -921,16 +939,14 @@ def trans_generate(lang, modules, cr):
|
|||||||
if not callable(msg):
|
if not callable(msg):
|
||||||
push_translation(encode(module), term_type, encode(model), 0, msg)
|
push_translation(encode(module), term_type, encode(model), 0, msg)
|
||||||
|
|
||||||
def push_local_constraints(module, model, cons_type='sql_constraints'):
|
def push_local_constraints(module, model):
|
||||||
""" Climb up the class hierarchy and ignore inherited constraints from other modules. """
|
""" Climb up the class hierarchy and ignore inherited constraints from other modules. """
|
||||||
term_type = 'sql_constraint' if cons_type == 'sql_constraints' else 'constraint'
|
|
||||||
msg_pos = 2 if cons_type == 'sql_constraints' else 1
|
|
||||||
for cls in model.__class__.__mro__:
|
for cls in model.__class__.__mro__:
|
||||||
if getattr(cls, '_module', None) != module:
|
if getattr(cls, '_module', None) != module:
|
||||||
continue
|
continue
|
||||||
constraints = getattr(cls, '_local_' + cons_type, [])
|
constraints = getattr(cls, '_local_constraints', [])
|
||||||
for constraint in constraints:
|
for constraint in constraints:
|
||||||
push_constraint_msg(module, term_type, model._name, constraint[msg_pos])
|
push_constraint_msg(module, 'constraint', model._name, constraint[1])
|
||||||
|
|
||||||
cr.execute(query_models, query_param)
|
cr.execute(query_models, query_param)
|
||||||
|
|
||||||
@@ -940,9 +956,7 @@ def trans_generate(lang, modules, cr):
|
|||||||
continue
|
continue
|
||||||
Model = env[model]
|
Model = env[model]
|
||||||
if Model._constraints:
|
if Model._constraints:
|
||||||
push_local_constraints(module, Model, 'constraints')
|
push_local_constraints(module, Model)
|
||||||
if Model._sql_constraints:
|
|
||||||
push_local_constraints(module, Model, 'sql_constraints')
|
|
||||||
|
|
||||||
installed_modules = [
|
installed_modules = [
|
||||||
m['name']
|
m['name']
|
||||||
|
|||||||
Reference in New Issue
Block a user