diff --git a/trytond/trytond/ir/__init__.py b/trytond/trytond/ir/__init__.py index 77afb9c8399..820ca9690de 100644 --- a/trytond/trytond/ir/__init__.py +++ b/trytond/trytond/ir/__init__.py @@ -12,7 +12,8 @@ def register(): Pool.register( - configuration.Configuration, + configuration.Configuration, # Must be registered first, see + # `__register__` implementation translation.Translation, translation.TranslationSetStart, translation.TranslationSetSucceed, diff --git a/trytond/trytond/ir/configuration.py b/trytond/trytond/ir/configuration.py index b1569cd46a6..00d6c898284 100644 --- a/trytond/trytond/ir/configuration.py +++ b/trytond/trytond/ir/configuration.py @@ -3,6 +3,7 @@ from trytond.cache import Cache from trytond.config import config from trytond.model import ModelSingleton, ModelSQL, fields +from trytond.transaction import Transaction class Configuration(ModelSingleton, ModelSQL): @@ -12,6 +13,15 @@ class Configuration(ModelSingleton, ModelSQL): hostname = fields.Char("Hostname", strip=False) _get_language_cache = Cache('ir_configuration.get_language') + @classmethod + def __register__(cls, module_name): + # This migration must be done before any translation creation takes + # place + cursor = Transaction().connection.cursor() + cursor.execute( + "ALTER TABLE ir_translation ALTER COLUMN res_id DROP NOT NULL") + super().__register__(module_name) + @staticmethod def default_language(): return config.get('database', 'language') diff --git a/trytond/trytond/ir/message.xml b/trytond/trytond/ir/message.xml index 2baecf7c3a5..f925358790b 100644 --- a/trytond/trytond/ir/message.xml +++ b/trytond/trytond/ir/message.xml @@ -408,5 +408,11 @@ this repository contains the full copyright notices and license terms. --> %(field)s (model name) + + The translation name must be unique by language and type when it's not related to a record. + + + The translation name must be unique by language, type and source when it's not related to a record. + diff --git a/trytond/trytond/ir/translation.py b/trytond/trytond/ir/translation.py index 115c6ed7d47..d4cb197eca2 100644 --- a/trytond/trytond/ir/translation.py +++ b/trytond/trytond/ir/translation.py @@ -61,7 +61,7 @@ class Translation(ModelSQL, ModelView): __name__ = "ir.translation" name = fields.Char('Field Name', required=True) - res_id = fields.Integer('Resource ID', required=True) + res_id = fields.Integer('Resource ID', domain=[('res_id', '>=', 0)]) lang = fields.Selection('get_language', string='Language') type = fields.Selection(TRANSLATION_TYPE, string='Type', required=True) @@ -120,6 +120,11 @@ def __register__(cls, module_name): table.drop_constraint('translation_md5_uniq') table.drop_column('src_md5') + # Migration from 7.2 + cursor.execute(*ir_translation.update( + [ir_translation.res_id], [Null], + where=(ir_translation.res_id == -1))) + super(Translation, cls).__register__(module_name) # Migration from 3.8: rename odt type in report @@ -162,7 +167,7 @@ def register_model(cls, model, module_name): 'value', 'module', 'fuzzy', 'res_id')], [[ name, INTERNAL_LANG, 'model', src, - '', module_name, False, -1]])) + '', module_name, False, Null]])) else: cursor.execute(*ir_translation.update( [ir_translation.src], @@ -210,7 +215,7 @@ def insert(field, type, name, string): *ir_translation.insert(columns, [[ name, INTERNAL_LANG, type, val, - '', module_name, False, -1]])) + '', module_name, False, Null]])) inserted = True for field_name, field in model._fields.items(): @@ -251,7 +256,7 @@ def update_insert_button(state_name, button): trans_name, INTERNAL_LANG, 'wizard_button', button.string, '', module_name, - False, -1]])) + False, Null]])) elif trans_buttons[trans_name] != button.string: cursor.execute(*ir_translation.update( [ir_translation.src], @@ -269,10 +274,6 @@ def update_insert_button(state_name, button): def default_fuzzy(): return False - @staticmethod - def default_res_id(): - return -1 - def get_model(self, name): return self.name.split(',')[0] @@ -614,7 +615,7 @@ def get_sources(cls, args): ('value', '!=', ''), ('value', '!=', None), ('fuzzy', '=', False), - ('res_id', '=', -1), + ('res_id', '=', None), ] if source is not None: clause.append(('src', '=', source)) @@ -655,7 +656,7 @@ def get_report(cls, report_name, text): ('value', '!=', ''), ('value', '!=', None), ('fuzzy', '=', False), - ('res_id', '=', -1), + ('res_id', '=', None), ], order=[('module', 'DESC')]) for translation in translations: cache.setdefault(translation.src, translation.value) @@ -799,7 +800,7 @@ def override_translation(ressource_id, new_translation): ]) res_id = model_data.db_id else: - res_id = -1 + res_id = None with Transaction().set_context(module=res_id_module): domain = [ ('name', '=', new_translation.name), @@ -864,14 +865,16 @@ def override_translation(ressource_id, new_translation): if (model in fs_id2prop and res_id in fs_id2prop[model]): res_id, noupdate = fs_id2prop[model][res_id] + elif res_id: + continue if res_id: try: res_id = int(res_id) except ValueError: - res_id = None - if not res_id: - res_id = -1 + continue + else: + res_id = None translation.res_id = res_id key = translation.unique_key @@ -954,7 +957,7 @@ def translation_export(cls, lang, module): 'name': translation.name, } res_id = translation.res_id - if res_id >= 0: + if res_id: model, _ = translation.name.split(',') if model in db_id2fs_id: res_id = db_id2fs_id[model].get(res_id) @@ -1135,7 +1138,7 @@ def set_report(self): report.report_name, INTERNAL_LANG, 'report', string, '', module, - False, -1]])) + False, Null]])) for (report_name, module), strings in report_strings.items(): query = translation.delete( where=(translation.name == report_name) @@ -1234,7 +1237,7 @@ def set_view(self): view.model, INTERNAL_LANG, 'view', string, '', view.module, - False, -1]])) + False, Null]])) if strings: cursor.execute(*translation.delete( where=(translation.name == view.model) @@ -1301,7 +1304,7 @@ def _clean_model(translation): Model = pool.get(model_name) except KeyError: return True - if translation.res_id >= 0: + if translation.res_id: if field_name not in Model._fields: return True field = Model._fields[field_name] @@ -1413,7 +1416,7 @@ def transition_clean(self): to_delete.append(translation.id) else: keys.add(key) - if translation.type == 'model' and translation.res_id >= 0: + if translation.type == 'model' and translation.res_id: model_name, _ = translation.name.split(',', 1) records[model_name][translation.res_id].add(translation.id) @@ -1606,7 +1609,7 @@ def do_update(self, action): where=(translation.name == row['name']) & (translation.type == row['type']) & (translation.lang == lang) - & (translation.res_id == (row['res_id'] or -1)) + & (translation.res_id == row['res_id']) & (translation.module == row['module']))) cursor.execute(*translation.select( diff --git a/trytond/trytond/tests/test_model.py b/trytond/trytond/tests/test_model.py index ef1babffe62..2d1ab3148c2 100644 --- a/trytond/trytond/tests/test_model.py +++ b/trytond/trytond/tests/test_model.py @@ -326,7 +326,6 @@ def test_fields_get(self): 'lang': self.other_language, 'src': "Name", 'name': 'test.model,name', - 'res_id': -1, 'value': "Nom", 'type': 'field', }])