Merge with trunk-server

bzr revid: ysa@tinyerp.com-20110107044915-4gm76atusr9p1ixz
bzr revid: ysa@tinyerp.com-20110110043822-bafoagz3t7d7pdue
This commit is contained in:
Yogesh Sakhreliya
2011-01-10 10:08:22 +05:30
23 changed files with 459 additions and 324 deletions
+32 -26
View File
@@ -610,18 +610,14 @@ class MigrationManager(object):
log = logging.getLogger('init')
def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=False, **kwargs):
def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=None, **kwargs):
"""Migrates+Updates or Installs all module nodes from ``graph``
:param graph: graph of module nodes to load
:param status: status dictionary for keeping track of progress
:param perform_checks: whether module descriptors should be checked for validity (prints warnings
for same cases, and even raise osv_except if certificate is invalid)
:param skip_cleanup: whether the auto-cleanup of records should be executed (unlinks any object that
appears to be from one of the updated modules, but have not been loaded during
last loading (i.e. records that seem to have been removed from the module).
This is best left disabled when loading stand-alone modules that could contain
records from dependent modules (i.e. other modules have put records in their
namespace)
:param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped
:return: list of modules that were installed or updated
"""
def process_sql_file(cr, fp):
queries = fp.read().split(';')
@@ -707,18 +703,16 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
status = {}
status = status.copy()
package_todo = []
processed_modules = []
statusi = 0
pool = pooler.get_pool(cr.dbname)
migrations = MigrationManager(cr, graph)
has_updates = False
modobj = None
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph))
for package in graph:
if skip_modules and package.name in skip_modules:
continue
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading objects' % package.name)
migrations.migrate_module(package, 'pre')
register_class(package.name)
@@ -732,6 +726,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
m = package.name
mid = package.id
if skip_modules and m in skip_modules:
continue
if modobj is None:
modobj = pool.get('ir.module.module')
@@ -746,7 +743,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
mode = 'init'
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
has_updates = True
for kind in ('init', 'update'):
if package.state=='to upgrade':
# upgrading the module information
@@ -765,7 +761,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
# as there is no rollback.
load_test(cr, m, idref, mode)
package_todo.append(package.name)
processed_modules.append(package.name)
migrations.migrate_module(package, 'post')
@@ -785,16 +781,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
statusi += 1
cr.execute('select model from ir_model where state=%s', ('manual',))
for model in cr.dictfetchall():
pool.get('ir.model').instanciate(cr, 1, model['model'], {})
if not skip_cleanup:
# Cleanup orphan records
pool.get('ir.model.data')._process_end(cr, 1, package_todo)
cr.commit()
return has_updates
return processed_modules
def _check_module_names(cr, module_names):
mod_names = set(module_names)
@@ -826,23 +815,30 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
force = []
if force_demo:
force.append('demo')
# This is a brand new pool, just created in pooler.get_db_and_pool()
pool = pooler.get_pool(cr.dbname)
try:
processed_modules = []
report = tools.assertion_report()
# NOTE: Try to also load the modules that have been marked as uninstallable previously...
STATES_TO_LOAD = ['installed', 'to upgrade', 'uninstallable']
if 'base' in tools.config['update']:
cr.execute("update ir_module_module set state=%s where name=%s", ('to upgrade', 'base'))
# STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
graph = create_graph(cr, ['base'], force)
if not graph:
logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
has_updates = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report, skip_cleanup=True)
processed_modules.extend(load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report))
if tools.config['load_language']:
for lang in tools.config['load_language'].split(','):
tools.load_language(cr, lang)
# STEP 2: Mark other modules to be loaded/updated
if update_module:
modobj = pool.get('ir.module.module')
logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
@@ -867,6 +863,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
STATES_TO_LOAD += ['to install']
# STEP 3: Load marked modules (skipping base which was done in STEP 1)
loop_guardrail = 0
while True:
loop_guardrail += 1
@@ -884,10 +882,15 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
break
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))
r = load_module_graph(cr, graph, status, report=report)
has_updates = has_updates or r
processed_modules.extend(load_module_graph(cr, graph, status, report=report, skip_modules=processed_modules))
# STEP 4: Finish and cleanup
if processed_modules:
# load custom models
cr.execute('select model from ir_model where state=%s', ('manual',))
for model in cr.dictfetchall():
pool.get('ir.model').instanciate(cr, 1, model['model'], {})
if has_updates:
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
for (model, name) in cr.fetchall():
model_obj = pool.get(model)
@@ -910,6 +913,9 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
else:
logger.notifyChannel('init', netsvc.LOG_WARNING, "Model %s is referenced but not present in the orm pool!" % model)
# Cleanup orphan records
pool.get('ir.model.data')._process_end(cr, 1, processed_modules)
if report.get_report():
logger.notifyChannel('init', netsvc.LOG_INFO, report)
+2
View File
@@ -28,6 +28,8 @@
<field name="translatable">True</field>
</record>
<function name="install_lang" model="res.lang"/>
<record id="ad" model="res.country">
<field name="name">Andorra, Principality of</field>
<field name="code">ad</field>
+1 -31
View File
@@ -70,34 +70,6 @@
======================
-->
<record id="view_change_user_password_form" model="ir.ui.view">
<field name="name">change.user.password</field>
<field name="model">change.user.password</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Change Password">
<field name="current_password" password="True" readonly="0" colspan="4"/>
<field name="new_password" password="True" readonly="0" colspan="4"/>
<field name="confirm_password" password="True" readonly="0" colspan="4"/>
<label colspan="1" string=""/>
<label colspan="3" string="You must logout and login again after changing your password."/>
<separator colspan="4" />
<label align="0.0" colspan="2" string=""/>
<button colspan="1" icon="gtk-cancel" special="cancel" string="Cancel"/>
<button colspan="1" icon="gtk-ok" name="change_password" string="Change" type="object"/>
</form>
</field>
</record>
<record id="action_view_change_password_form" model="ir.actions.act_window">
<field name="name">Change Password</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">change.user.password</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="view_users_form_simple_modif" model="ir.ui.view">
<field name="name">res.users.form.modif</field>
<field name="model">res.users</field>
@@ -119,8 +91,6 @@
<field name="context_lang" completion="1" readonly="0"/>
<field name="context_tz" completion="1" readonly="0"/>
<field name="menu_tips" colspan="2" readonly="0"/>
<label string="" colspan="1"/>
<button name="%(action_view_change_password_form)d" string="Change Password" type="action" icon="gtk-execute"/>
<separator string="Email &amp; Signature" colspan="4"/>
<group colspan="4"><field name="user_email" widget="email" readonly="0"/></group>
<field colspan="4" name="signature" readonly="0" nolabel="1"/>
@@ -139,7 +109,7 @@
<field name="name" select="1"/>
<field name="active"/>
<field name="login" select="1"/>
<field name="password" password="True"/>
<field name="new_password" password="True"/>
<newline/>
<notebook colspan="4">
<page string="User">
+21 -10
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-03 16:57+0000\n"
"PO-Revision-Date: 2011-01-04 19:55+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
"PO-Revision-Date: 2011-01-07 14:52+0000\n"
"Last-Translator: Quentin THEURET <quentin@theuret.net>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-01-05 04:44+0000\n"
"X-Launchpad-Export-Date: 2011-01-08 04:55+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -2913,7 +2913,7 @@ msgstr "Objet déclencheur"
#. module: base
#: help:change.user.password,confirm_password:0
msgid "Enter the new password again for confirmation."
msgstr ""
msgstr "Entrer le mot de passe à nouveau pour confirmer."
#. module: base
#: view:res.users:0
@@ -4618,6 +4618,10 @@ msgid ""
"OpenERP. They are launched during the installation of new modules, but you "
"can choose to restart some wizards manually from this menu."
msgstr ""
"Les assistants de configuration sont utilisés pour vous aider à configurer "
"une nouvelle instance OpenERP. Ils sont lancés lors de l'installation de "
"nouveaux modules mais vous pouvez choisir de les déclencher manuellement à "
"partir de ce menu."
#. module: base
#: code:addons/orm.py:1350
@@ -5185,7 +5189,7 @@ msgstr "Valeurs pour le type d'évènement"
#: code:addons/base/res/res_user.py:605
#, python-format
msgid "The current password does not match, please double-check it."
msgstr ""
msgstr "Le mot de passe actuel ne correspond pas, vérifiez de nouveau."
#. module: base
#: selection:ir.model.fields,select_level:0
@@ -6151,7 +6155,7 @@ msgstr "Codes de la Séquence"
#. module: base
#: field:change.user.password,confirm_password:0
msgid "Confirm Password"
msgstr ""
msgstr "Confirmer le mot de passe"
#. module: base
#: selection:base.language.install,lang:0
@@ -6334,6 +6338,8 @@ msgstr "Îles Pitcairn"
msgid ""
"The new and confirmation passwords do not match, please double-check them."
msgstr ""
"Le nouveau mot de passe et la confirmation ne correspondent pas. Vérifiez de "
"nouveau."
#. module: base
#: view:base.module.upgrade:0
@@ -6425,7 +6431,7 @@ msgstr "Terminé"
#. module: base
#: view:change.user.password:0
msgid "Change"
msgstr ""
msgstr "Modifier"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_miss
@@ -7392,7 +7398,7 @@ msgstr "Avertissement !"
#. module: base
#: model:res.widget,title:base.google_maps_widget
msgid "Google Maps"
msgstr ""
msgstr "Google Maps"
#. module: base
#: model:ir.ui.menu,name:base.menu_base_config
@@ -7574,7 +7580,7 @@ msgstr "Sélection"
#: model:ir.actions.act_window,name:base.action_view_change_password_form
#: view:res.users:0
msgid "Change Password"
msgstr ""
msgstr "Modifier le mot de passe"
#. module: base
#: field:res.company,rml_header1:0
@@ -7831,7 +7837,7 @@ msgstr "Croate / hrvatski jezik"
#. module: base
#: help:change.user.password,current_password:0
msgid "Enter your current password."
msgstr ""
msgstr "Entrez votre mot de passe actuel."
#. module: base
#: field:base.language.install,overwrite:0
@@ -9101,6 +9107,11 @@ msgid ""
"uncheck the 'Suppliers' filter button in order to search in all your "
"partners, including customers and prospects."
msgstr ""
"Vous pouvez accéder à toutes les informations fournisseur grâce à son "
"formulaire : données comptables, historique des courriels, rendez-vous, "
"achats, etc. Vous pouvez désélectionner le boutton \"Fournisseur\" afin de "
"chercher dans la totalité de vos partenaires, incluant les clients et les "
"opportunités."
#. module: base
#: model:res.country,name:base.rw
+111 -54
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-03 16:57+0000\n"
"PO-Revision-Date: 2010-12-19 08:29+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"PO-Revision-Date: 2011-01-07 13:38+0000\n"
"Last-Translator: Douwe Wullink (Dypalio) <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-01-04 14:03+0000\n"
"X-Launchpad-Export-Date: 2011-01-08 04:54+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -47,6 +47,8 @@ msgid ""
"The second argument of the many2many field %s must be a SQL table !You used "
"%s, which is not a valid SQL table name."
msgstr ""
"Het tweede argument van het many2many veld %s moet een SQL tabel zijn ! U "
"gebruikte %s, wat geen geldige SQL tabelnaam is."
#. module: base
#: view:ir.values:0
@@ -117,6 +119,8 @@ msgid ""
"You can not write in this document (%s) ! Be sure your user belongs to one "
"of these groups: %s."
msgstr ""
"U kunt niet schrijven in dit document (%s) ! Controleer of uw gebruiker "
"behoort bij één van deze groepen: %s."
#. module: base
#: field:res.partner,ref:0
@@ -154,7 +158,7 @@ msgstr "Swaziland"
#: code:addons/orm.py:3653
#, python-format
msgid "created."
msgstr ""
msgstr "gemaakt."
#. module: base
#: model:res.partner.category,name:base.res_partner_category_woodsuppliers0
@@ -260,7 +264,7 @@ msgstr "Naam assistent"
#: code:addons/orm.py:2160
#, python-format
msgid "Invalid group_by"
msgstr ""
msgstr "Ongeldige group_by"
#. module: base
#: field:res.partner,credit_limit:0
@@ -383,7 +387,7 @@ msgstr ""
#: code:addons/orm.py:904
#, python-format
msgid "The read method is not implemented on this object !"
msgstr ""
msgstr "De read methode is niet in dit object geïmplementeerd !"
#. module: base
#: help:res.lang,iso_code:0
@@ -417,7 +421,7 @@ msgstr "Upgrade inplannen"
#: code:addons/orm.py:838
#, python-format
msgid "Key/value '%s' not found in selection field '%s'"
msgstr ""
msgstr "Sleutel/waarde '%s' niet gevonden in selectie veld '%s'"
#. module: base
#: help:res.country,code:0
@@ -724,7 +728,7 @@ msgstr ""
#: code:addons/orm.py:1043
#, python-format
msgid "The unlink method is not implemented on this object !"
msgstr ""
msgstr "De unlink-methode is niet geïmplementeerd voor dit object !"
#. module: base
#: model:ir.actions.act_window,name:base.act_menu_create
@@ -797,6 +801,8 @@ msgid ""
"Language with code \"%s\" is not defined in your system !\n"
"Define it through the Administration menu."
msgstr ""
"Taal met code \"%s\" is niet gedefinieerd in uw systeem !\n"
"Definieer het via het Beheer menu."
#. module: base
#: model:res.country,name:base.gu
@@ -835,7 +841,7 @@ msgstr "Overgangen"
#: code:addons/orm.py:4020
#, python-format
msgid "Record #%d of %s not found, cannot copy!"
msgstr ""
msgstr "Record #%d van %s niet gevonden, kan niet kopieren!"
#. module: base
#: field:ir.module.module,contributors:0
@@ -1065,7 +1071,7 @@ msgstr ""
#: code:addons/orm.py:1744
#, python-format
msgid "The search method is not implemented on this object !"
msgstr ""
msgstr "De search-methode is niet in dit object geïmplementeerd !"
#. module: base
#: view:wizard.ir.model.menu.create:0
@@ -1461,7 +1467,7 @@ msgstr ""
#: code:addons/fields.py:114
#, python-format
msgid "Not implemented search_memory method !"
msgstr ""
msgstr "Niet geïmplementeerde search_method methode !"
#. module: base
#: view:res.log:0
@@ -1541,7 +1547,7 @@ msgstr "Aantal bijgewerkte modules"
#: code:addons/fields.py:100
#, python-format
msgid "Not implemented set_memory method !"
msgstr ""
msgstr "Niet geïmplenteerde set_memory methode !"
#. module: base
#: view:workflow.activity:0
@@ -1560,7 +1566,7 @@ msgstr ""
#. module: base
#: field:change.user.password,new_password:0
msgid "New Password"
msgstr ""
msgstr "Nieuw wachtwoord"
#. module: base
#: model:ir.actions.act_window,help:base.action_ui_view
@@ -1637,6 +1643,7 @@ msgstr ""
#, python-format
msgid "A document was modified since you last viewed it (%s:%d)"
msgstr ""
"Een document is gewijzigd nadat u het voor het laatst heeft bekeken (%s:%d)"
#. module: base
#: view:workflow:0
@@ -1875,7 +1882,7 @@ msgstr ""
#: code:addons/orm.py:1040
#, python-format
msgid "The perm_read method is not implemented on this object !"
msgstr ""
msgstr "De perm_read methode is niet in dit object geïmplementeerd !"
#. module: base
#: view:res.lang:0
@@ -1896,7 +1903,7 @@ msgstr "Pakistan"
#: code:addons/orm.py:1350
#, python-format
msgid "Invalid Object Architecture!"
msgstr ""
msgstr "Ongeldige object architectuur!"
#. module: base
#: model:ir.ui.menu,name:base.menu_email_gateway_form
@@ -1941,6 +1948,8 @@ msgid ""
"One of the records you are trying to modify has already been deleted "
"(Document type: %s)."
msgstr ""
"Een van de records die u probeert te wijzigen is al verwijderd )document "
"type: %s)."
#. module: base
#: model:ir.actions.act_window,help:base.action_country
@@ -2008,7 +2017,7 @@ msgstr "Cuba"
#. module: base
#: model:res.widget,title:base.facebook_widget
msgid "Facebook"
msgstr ""
msgstr "Facebook"
#. module: base
#: model:res.country,name:base.am
@@ -2119,6 +2128,9 @@ msgid ""
"separated list of valid field names (optionally followed by asc/desc for the "
"direction)"
msgstr ""
"Ongeldige \"order\" opgegeven. Een geldige \"order\" specificatie is een "
"comma-gescheiden lijst van geldige veldnamen (optioneel gevolgd door "
"asc/desc voor de richting)"
#. module: base
#: model:ir.model,name:base.model_ir_module_module_dependency
@@ -2179,7 +2191,7 @@ msgstr "Moederorganisatie"
#. module: base
#: field:ir.ui.menu,web_icon_hover:0
msgid "Web Icon File (hover)"
msgstr ""
msgstr "Web icon bestand (hover)"
#. module: base
#: view:ir.actions.server:0
@@ -2274,7 +2286,7 @@ msgstr "De heer"
#: code:addons/orm.py:1622
#, python-format
msgid "There is no view of type '%s' defined for the structure!"
msgstr ""
msgstr "Er is geen weergave soort '%s' gedefinieerd voor de structuur!"
#. module: base
#: field:ir.default,ref_id:0
@@ -2400,7 +2412,7 @@ msgstr "Filters"
#: code:addons/orm.py:758
#, python-format
msgid "Please check that all your lines have %d columns."
msgstr ""
msgstr "Controleer aub of alle regels %d kolummen hebben."
#. module: base
#: model:ir.actions.act_window,name:base.ir_cron_act
@@ -2426,7 +2438,7 @@ msgstr ""
#: code:addons/orm.py:3448
#, python-format
msgid "Recursivity Detected."
msgstr ""
msgstr "Recursiviteit ontdekt."
#. module: base
#: code:addons/base/module/module.py:262
@@ -2462,7 +2474,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_maintenance_contract
msgid "maintenance.contract"
msgstr ""
msgstr "maintenance.contract"
#. module: base
#: model:res.country,name:base.ru
@@ -2534,7 +2546,7 @@ msgstr "%x - Passende datum weergave"
#. module: base
#: model:ir.model,name:base.model_change_user_password
msgid "change.user.password"
msgstr ""
msgstr "change.user.password"
#. module: base
#: view:res.lang:0
@@ -2573,6 +2585,8 @@ msgid ""
"Operation prohibited by access rules, or performed on an already deleted "
"document (Operation: read, Document type: %s)."
msgstr ""
"Bewerking geweigerd door toegangsregels, of uitgevoerd op een al verwijderd "
"document (Bewerking: lezen, Documentsoort: %s)."
#. module: base
#: model:res.country,name:base.nr
@@ -2663,7 +2677,7 @@ msgstr "EAN13"
#: code:addons/orm.py:1622
#, python-format
msgid "Invalid Architecture!"
msgstr ""
msgstr "Ongeldige architectuur!"
#. module: base
#: model:res.country,name:base.pt
@@ -2886,7 +2900,7 @@ msgstr "Trigger-object"
#. module: base
#: help:change.user.password,confirm_password:0
msgid "Enter the new password again for confirmation."
msgstr ""
msgstr "Voer het nieuwe wachtwoord nogmaals in ter bevestiging."
#. module: base
#: view:res.users:0
@@ -3164,7 +3178,7 @@ msgstr "Systeemconfiguratie afgerond"
#: code:addons/orm.py:929
#, python-format
msgid "Error occurred while validating the field(s) %s: %s"
msgstr ""
msgstr "Fout opgetreden bij het valideren van veld(en) %s: %s"
#. module: base
#: view:ir.property:0
@@ -3234,6 +3248,8 @@ msgid ""
"You can not create this document (%s) ! Be sure your user belongs to one of "
"these groups: %s."
msgstr ""
"U kunt dit document (%s) niet maken ! Controleer of uw gebruiker behoort tot "
"één van deze groepen: %s."
#. module: base
#: model:res.country,name:base.mu
@@ -3460,6 +3476,12 @@ msgid ""
"Would your payment have been carried out after this mail was sent, please "
"consider the present one as void."
msgstr ""
"Merk op dat de volgende betalingen nu vervallen zijn. Als uw betaling als is "
"verstuurd, wilt u daar dan de details van sturen. Als betaling verder wordt "
"uitgesteld, wilt u dan contact opnemen voor overleg. "
"\n"
"Is uw betaling uitgevoerd voordat deze mail was gestuurd, wilt u deze dan "
"als niet verstuurd beschouwen."
#. module: base
#: model:res.country,name:base.mx
@@ -3490,7 +3512,7 @@ msgstr "Nicaragua"
#: code:addons/orm.py:1046
#, python-format
msgid "The write method is not implemented on this object !"
msgstr ""
msgstr "De write-methode is niet geïmplementeerd in dit object !"
#. module: base
#: view:res.partner.event:0
@@ -3573,6 +3595,14 @@ msgid ""
"plugin, don't forget to register emails to each contact so that the gateway "
"will automatically attach incoming emails to the right partner."
msgstr ""
"Een klant is een entiteit waar u zaken mee doet, zoals een bedrijf of een "
"organisatie. Een klant kan verschillende contactpersonen of adressen hebben "
"wat de mensen zijn die voor het bedrijf werken. U kunt het geschiedenis "
"tabblad gebruiken om alle aan de klant gerelateerde transacties te volgen: "
"verkooporder, emails, verkoopkansen, klachten, etc. Als u de email gateway, "
"de outlook- of thunderbird plugin gebruikt, vergeet dan niet om emails van "
"iedere contactpersoon vast te leggen zodat de gateway inkomende email "
"automatisch koppelt aan de juiste relatie."
#. module: base
#: field:ir.actions.report.xml,name:0
@@ -3967,13 +3997,14 @@ msgstr "ir.actions.url"
#. module: base
#: model:res.widget,title:base.currency_converter_widget
msgid "Currency Converter"
msgstr ""
msgstr "Valuta omzetter"
#. module: base
#: code:addons/orm.py:156
#, python-format
msgid "Wrong ID for the browse record, got %r, expected an integer."
msgstr ""
"Onjuist ID voor het te bekijken record. Ontving %r, verwachtte een integer."
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_addess_tree
@@ -4011,7 +4042,7 @@ msgstr "Frans / Français"
#: code:addons/orm.py:1049
#, python-format
msgid "The create method is not implemented on this object !"
msgstr ""
msgstr "De create-methode is niet in dit object geïmplementeerd !"
#. module: base
#: field:workflow.triggers,workitem_id:0
@@ -4275,6 +4306,8 @@ msgid ""
"You cannot perform this operation. New Record Creation is not allowed for "
"this object as this object is for reporting purpose."
msgstr ""
"U kunt deze bewerking niet uitvoeren. Nieuw record maken is niet toegestaan "
"voor dit object omdat dit object voor rapportage doelen is."
#. module: base
#: view:base.language.import:0
@@ -4318,7 +4351,7 @@ msgstr "Project"
#. module: base
#: field:ir.ui.menu,web_icon_hover_data:0
msgid "Web Icon Image (hover)"
msgstr ""
msgstr "Web icon afbeelding (hover)"
#. module: base
#: view:base.module.import:0
@@ -4380,7 +4413,7 @@ msgstr "Aanmaken"
#. module: base
#: field:change.user.password,current_password:0
msgid "Current Password"
msgstr ""
msgstr "Huidig wachtwoord"
#. module: base
#: field:res.partner.address,state_id:0
@@ -4473,7 +4506,7 @@ msgstr "Ondertekening"
#: code:addons/fields.py:664
#, python-format
msgid "Not Implemented"
msgstr ""
msgstr "Niet geïmplementeerd"
#. module: base
#: model:ir.model,name:base.model_res_widget_user
@@ -4542,6 +4575,8 @@ msgstr "Contactpersonen"
msgid ""
"Unable to delete this document because it is used as a default property"
msgstr ""
"Dit document kan niet worden verwijderd omdat het in gebruik is als "
"standaard eigenschap"
#. module: base
#: view:res.widget.wizard:0
@@ -4577,12 +4612,16 @@ msgid ""
"OpenERP. They are launched during the installation of new modules, but you "
"can choose to restart some wizards manually from this menu."
msgstr ""
"De configuratie assistenten worden gebruikt om u te helpen bij het "
"configureren van een nieuw exemplaar van OpenERP. Ze worden gestart "
"gedurende de installatie van nieuwe modules, maar u kunt ervoor kiezen om "
"sommige assistenten handmatig in het menu te herstarten."
#. module: base
#: code:addons/orm.py:1350
#, python-format
msgid "Insufficient fields for Calendar View!"
msgstr ""
msgstr "Onvoldoende velden voor agenda weergave!"
#. module: base
#: selection:ir.property,type:0
@@ -5002,7 +5041,7 @@ msgstr "Cliënt acties"
#: code:addons/orm.py:1806
#, python-format
msgid "The exists method is not implemented on this object !"
msgstr ""
msgstr "De exists-methode is niet in dit object geimplementeerd !"
#. module: base
#: code:addons/base/module/module.py:336
@@ -5134,7 +5173,7 @@ msgstr "Geaccepteerde gebruikers"
#. module: base
#: field:ir.ui.menu,web_icon_data:0
msgid "Web Icon Image"
msgstr ""
msgstr "Web icon afbeelding"
#. module: base
#: view:ir.values:0
@@ -5145,7 +5184,7 @@ msgstr "Waarde voor soort gebeurtenis"
#: code:addons/base/res/res_user.py:605
#, python-format
msgid "The current password does not match, please double-check it."
msgstr ""
msgstr "Het huidige wachtwoord klopt niet, controleer het nog eens."
#. module: base
#: selection:ir.model.fields,select_level:0
@@ -5269,6 +5308,8 @@ msgid ""
"Invalid value for reference field \"%s\" (last part must be a non-zero "
"integer): \"%s\""
msgstr ""
"Ongeldige waarde voor referentie veld \"%s\" (laatste deel moet een niet-nul "
"integer zijn): \"%s\""
#. module: base
#: help:ir.cron,args:0
@@ -5339,7 +5380,7 @@ msgstr "Thais / ภาษาไทย"
#: code:addons/orm.py:158
#, python-format
msgid "Object %s does not exists"
msgstr ""
msgstr "Object %s bestaat niet"
#. module: base
#: selection:base.language.install,lang:0
@@ -5476,7 +5517,7 @@ msgstr "Herhaling"
#: code:addons/orm.py:3532
#, python-format
msgid "UserError"
msgstr ""
msgstr "Gebruikersfout"
#. module: base
#: model:res.country,name:base.ae
@@ -5546,7 +5587,7 @@ msgstr "8. %I:%M:%S %p ==> 06:25:20 PM"
#: code:addons/orm.py:1803
#, python-format
msgid "The copy method is not implemented on this object !"
msgstr ""
msgstr "De copy-methode is niet in dit object geïmplementeerd"
#. module: base
#: field:res.log,create_date:0
@@ -5758,7 +5799,7 @@ msgstr "U kunt geen taal verwijderen die gebruikers voorkeurstaal is !"
#: code:addons/fields.py:103
#, python-format
msgid "Not implemented get_memory method !"
msgstr ""
msgstr "Niet geïmplementeerde get_memory methode !"
#. module: base
#: view:ir.actions.server:0
@@ -5816,7 +5857,7 @@ msgstr "Actueel"
#. module: base
#: help:change.user.password,new_password:0
msgid "Enter the new password."
msgstr ""
msgstr "Het nieuwe wachtwoord invoeren."
#. module: base
#: model:res.partner.category,name:base.res_partner_category_9
@@ -6100,7 +6141,7 @@ msgstr "Reeks codes"
#. module: base
#: field:change.user.password,confirm_password:0
msgid "Confirm Password"
msgstr ""
msgstr "Wachtwoord bevestigen"
#. module: base
#: selection:base.language.install,lang:0
@@ -6185,7 +6226,7 @@ msgstr "Soort"
#: code:addons/orm.py:3775
#, python-format
msgid "This method does not exist anymore"
msgstr ""
msgstr "Deze methode bestaat niet meer"
#. module: base
#: field:res.bank,fax:0
@@ -6282,6 +6323,7 @@ msgstr "Pitcairn eiland"
msgid ""
"The new and confirmation passwords do not match, please double-check them."
msgstr ""
"Het nieuwe en bevestigde wachtwoord kloppen niet. Controleer ze nog eens."
#. module: base
#: view:base.module.upgrade:0
@@ -6373,7 +6415,7 @@ msgstr "Voltooid"
#. module: base
#: view:change.user.password:0
msgid "Change"
msgstr ""
msgstr "Wijzigen"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_miss
@@ -6472,6 +6514,8 @@ msgid ""
"You can not read this document (%s) ! Be sure your user belongs to one of "
"these groups: %s."
msgstr ""
"U kunt dit document (%s) niet lezen ! Controleer dat uw gebruiker behoort "
"tot één van deze groepen: %s."
#. module: base
#: view:res.bank:0
@@ -6637,7 +6681,7 @@ msgstr "Of"
#: model:ir.actions.act_window,name:base.res_log_act_window
#: model:ir.ui.menu,name:base.menu_res_log_act_window
msgid "Client Logs"
msgstr ""
msgstr "Klant logboek"
#. module: base
#: model:res.country,name:base.al
@@ -6686,7 +6730,7 @@ msgstr "Probleem in instellingen `Record id` in server-actie!"
#: code:addons/orm.py:2316
#, python-format
msgid "ValidateError"
msgstr ""
msgstr "Validatiefout"
#. module: base
#: view:base.module.import:0
@@ -6743,6 +6787,8 @@ msgid ""
"The sum of the data (2nd field) is null.\n"
"We can't draw a pie chart !"
msgstr ""
"De som van de data (2de veld) is nul.\n"
"Er kan geen taartdiagram worden getekend !"
#. module: base
#: model:ir.ui.menu,name:base.menu_lunch_reporting
@@ -6775,7 +6821,7 @@ msgstr "Alles stoppen"
#: code:addons/orm.py:412
#, python-format
msgid "The read_group method is not implemented on this object !"
msgstr ""
msgstr "De read_group-methode op dit object is niet geimplementeerd !"
#. module: base
#: view:ir.model.data:0
@@ -7080,7 +7126,7 @@ msgstr "Argumenten"
#: code:addons/orm.py:716
#, python-format
msgid "Database ID doesn't exist: %s : %s"
msgstr ""
msgstr "Database ID bestaat niet: %s : %s"
#. module: base
#: selection:ir.module.module,license:0
@@ -7096,7 +7142,7 @@ msgstr "GPL versie 3"
#: code:addons/orm.py:836
#, python-format
msgid "key '%s' not found in selection field '%s'"
msgstr ""
msgstr "sleutel '%s' niet gevonden in selectie veld '%s'"
#. module: base
#: view:partner.wizard.ean.check:0
@@ -7108,6 +7154,7 @@ msgstr "Correcte EAN13"
#, python-format
msgid "The value \"%s\" for the field \"%s\" is not in the selection"
msgstr ""
"De waarde \"%s\" voor het veld \"%s\" is niet opgenomen in de selectie"
#. module: base
#: field:res.partner,customer:0
@@ -7330,7 +7377,7 @@ msgstr "Waarschuwing !"
#. module: base
#: model:res.widget,title:base.google_maps_widget
msgid "Google Maps"
msgstr ""
msgstr "Google Maps"
#. module: base
#: model:ir.ui.menu,name:base.menu_base_config
@@ -7512,7 +7559,7 @@ msgstr "Selectie"
#: model:ir.actions.act_window,name:base.action_view_change_password_form
#: view:res.users:0
msgid "Change Password"
msgstr ""
msgstr "Wachtwoord wijzigen"
#. module: base
#: field:res.company,rml_header1:0
@@ -7634,7 +7681,7 @@ msgstr "workflow.instance"
#: code:addons/orm.py:278
#, python-format
msgid "Unknown attribute %s in %s "
msgstr ""
msgstr "Onbekend attribuut %s in %s "
#. module: base
#: view:res.lang:0
@@ -7645,7 +7692,7 @@ msgstr "10. %S ==> 20"
#: code:addons/fields.py:106
#, python-format
msgid "undefined get method !"
msgstr ""
msgstr "Ongedefinieerde get methode !"
#. module: base
#: selection:base.language.install,lang:0
@@ -7768,7 +7815,7 @@ msgstr "Croatisch / hrvatski jezik"
#. module: base
#: help:change.user.password,current_password:0
msgid "Enter your current password."
msgstr ""
msgstr "Huidige wachtwoord invoeren."
#. module: base
#: field:base.language.install,overwrite:0
@@ -8226,6 +8273,8 @@ msgid ""
"Operation prohibited by access rules, or performed on an already deleted "
"document (Operation: %s, Document type: %s)."
msgstr ""
"Bewerking geweigerd door toegangsregels of uitgevoerd op al verwijderd "
"document (Bewerking: %s, documentsoort: %s)."
#. module: base
#: model:res.country,name:base.zr
@@ -8562,6 +8611,8 @@ msgid ""
"Invalid group_by specification: \"%s\".\n"
"A group_by specification must be a list of valid fields."
msgstr ""
"Ongeldige group_by specificatie: \"%s\".\n"
"Een group_by specificatie moet een lijst van geldige velden zijn."
#. module: base
#: model:res.country,name:base.sa
@@ -8827,7 +8878,7 @@ msgstr "Bron"
#. module: base
#: field:ir.ui.menu,web_icon:0
msgid "Web Icon File"
msgstr ""
msgstr "Web Icon bestand"
#. module: base
#: selection:base.language.install,lang:0
@@ -8861,6 +8912,8 @@ msgid ""
"You can not delete this document (%s) ! Be sure your user belongs to one of "
"these groups: %s."
msgstr ""
"U kunt dit document (%s) niet verwijderen ! Controleer dat uw gebruiker "
"behoort tot één van deze groepen: %s."
#. module: base
#: model:ir.model,name:base.model_base_module_configuration
@@ -9029,6 +9082,10 @@ msgid ""
"uncheck the 'Suppliers' filter button in order to search in all your "
"partners, including customers and prospects."
msgstr ""
"U kunt alle informatie over uw leveranciers benaderen vanaf het "
"leveranciersformulier: financiele gegevens, geschiedenis van emails, "
"afspraken, inkopen, etc. U kunt de 'Leveranciers' filterknop uitzetten om in "
"al uw relaties te zoeken, inclusief klanten en prospects."
#. module: base
#: model:res.country,name:base.rw
+5 -5
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-03 16:57+0000\n"
"PO-Revision-Date: 2011-01-04 17:01+0000\n"
"PO-Revision-Date: 2011-01-07 19:16+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-01-05 04:45+0000\n"
"X-Launchpad-Export-Date: 2011-01-08 04:55+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -728,7 +728,7 @@ msgstr "Индия"
#: model:ir.actions.act_window,name:base.res_request_link-act
#: model:ir.ui.menu,name:base.menu_res_request_link_act
msgid "Request Reference Types"
msgstr ""
msgstr "Типы ссылок в запросе"
#. module: base
#: view:ir.values:0
@@ -7373,7 +7373,7 @@ msgstr "Выбор"
#: model:ir.actions.act_window,name:base.action_view_change_password_form
#: view:res.users:0
msgid "Change Password"
msgstr ""
msgstr "Изменить пароль"
#. module: base
#: field:res.company,rml_header1:0
@@ -7953,7 +7953,7 @@ msgstr "Иран"
#: model:ir.actions.act_window,name:base.res_widget_user_act_window
#: model:ir.ui.menu,name:base.menu_res_widget_user_act_window
msgid "Widgets per User"
msgstr ""
msgstr "Виджеты пользователей"
#. module: base
#: selection:base.language.install,lang:0
+11 -11
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-03 16:57+0000\n"
"PO-Revision-Date: 2011-01-05 07:12+0000\n"
"PO-Revision-Date: 2011-01-08 08:11+0000\n"
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-01-06 04:34+0000\n"
"X-Launchpad-Export-Date: 2011-01-09 04:50+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -636,7 +636,7 @@ msgstr "导入/导出"
#: help:ir.actions.act_window,domain:0
msgid ""
"Optional domain filtering of the destination data, as a Python expression"
msgstr ""
msgstr "一个可选的目标数据过滤条件,使用 Python 表达式表示"
#. module: base
#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade
@@ -1497,7 +1497,7 @@ msgstr ""
#. module: base
#: field:change.user.password,new_password:0
msgid "New Password"
msgstr ""
msgstr "新密码"
#. module: base
#: model:ir.actions.act_window,help:base.action_ui_view
@@ -1927,7 +1927,7 @@ msgstr "古巴"
#. module: base
#: model:res.widget,title:base.facebook_widget
msgid "Facebook"
msgstr ""
msgstr "Facebook"
#. module: base
#: model:res.country,name:base.am
@@ -2062,7 +2062,7 @@ msgid ""
"Manage the contact titles you want to have available in your system and the "
"way you want to print them in letters and other documents. Some example: "
"Mr., Mrs. "
msgstr ""
msgstr "管理您系统中可用的联系人称谓,这样您可以在信函或其它文档中使用它们,如:先生,女士 。 "
#. module: base
#: field:res.company,rml_footer1:0
@@ -2440,7 +2440,7 @@ msgstr "%x - 使用日期表示"
#. module: base
#: model:ir.model,name:base.model_change_user_password
msgid "change.user.password"
msgstr ""
msgstr "change.user.password"
#. module: base
#: view:res.lang:0
@@ -2694,7 +2694,7 @@ msgstr "待触发动作"
#: code:addons/base/res/res_user.py:136
#, python-format
msgid "\"email_from\" needs to be set to send welcome mails to users"
msgstr ""
msgstr "发送欢迎邮件必须设置 \"email_from\""
#. module: base
#: selection:ir.translation,type:0
@@ -2746,7 +2746,7 @@ msgstr "页眉/页脚"
msgid ""
"Optional help text for the users with a description of the target view, such "
"as its usage and purpose."
msgstr ""
msgstr "可选的帮助文本用于用户描述目标视图,比如用法和目的。"
#. module: base
#: model:res.country,name:base.va
@@ -2776,7 +2776,7 @@ msgstr "触发器对象"
#. module: base
#: help:change.user.password,confirm_password:0
msgid "Enter the new password again for confirmation."
msgstr ""
msgstr "再次输入新密码确认。"
#. module: base
#: view:res.users:0
@@ -3828,7 +3828,7 @@ msgstr "ir.actions.url"
#. module: base
#: model:res.widget,title:base.currency_converter_widget
msgid "Currency Converter"
msgstr ""
msgstr "货币转换器"
#. module: base
#: code:addons/orm.py:156
+46
View File
@@ -848,6 +848,52 @@
</record>
<menuitem action="action_ui_view" id="menu_action_ui_view" parent="base.next_id_2"/>
<!-- View customizations -->
<record id="view_view_custom_search" model="ir.ui.view">
<field name="name">ir.ui.view.custom.search</field>
<field name="model">ir.ui.view.custom</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Customized Views">
<field name="user_id"/>
<field name="ref_id"/>
</search>
</field>
</record>
<record id="view_view_custom_form" model="ir.ui.view">
<field name="name">ir.ui.view.custom.form</field>
<field name="model">ir.ui.view.custom</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Customized Views">
<field name="user_id"/>
<field name="ref_id"/>
<separator colspan="4" string="Customized Architecture"/>
<field name="arch" colspan="4" nolabel="1"/>
</form>
</field>
</record>
<record id="view_view_custom_tree" model="ir.ui.view">
<field name="name">ir.ui.view.custom.tree</field>
<field name="model">ir.ui.view.custom</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Customized Views">
<field name="user_id"/>
<field name="ref_id"/>
</tree>
</field>
</record>
<record id="action_ui_view_custom" model="ir.actions.act_window">
<field name="name">Customized Views</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.ui.view.custom</field>
<field name="help">Customized views are used when users reorganize the content of their dashboard views (via web client)</field>
</record>
<menuitem action="action_ui_view_custom" id="menu_action_ui_view_custom" parent="base.next_id_4"/>
<!-- Attachment -->
<record id="view_attachment_form" model="ir.ui.view">
<field name="name">ir.attachment.view</field>
+41 -12
View File
@@ -19,14 +19,16 @@
#
##############################################################################
import logging
import re
import time
from operator import itemgetter
from osv import fields,osv
import ir, re
import ir
import netsvc
from osv.orm import except_orm, browse_record
import time
import tools
from tools.safe_eval import safe_eval as eval
from tools import config
from tools.translate import _
import pooler
@@ -152,21 +154,29 @@ class ir_model_fields(osv.osv):
_description = "Fields"
_columns = {
'name': fields.char('Name', required=True, size=64, select=1),
'model': fields.char('Object Name', size=64, required=True, select=1),
'relation': fields.char('Object Relation', size=64),
'relation_field': fields.char('Relation Field', size=64),
'model_id': fields.many2one('ir.model', 'Object ID', required=True, select=True, ondelete='cascade'),
'model': fields.char('Object Name', size=64, required=True, select=1,
help="The technical name of the model this field belongs to"),
'relation': fields.char('Object Relation', size=64,
help="For relationship fields, the technical name of the target model"),
'relation_field': fields.char('Relation Field', size=64,
help="For one2many fields, the field on the target model that implement the opposite many2one relationship"),
'model_id': fields.many2one('ir.model', 'Model', required=True, select=True, ondelete='cascade',
help="The model this field belongs to"),
'field_description': fields.char('Field Label', required=True, size=256),
'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
'selection': fields.char('Field Selection',size=128),
'selection': fields.char('Selection Options',size=128, help="List of options for a selection field, "
"specified as a Python expression defining a list of (key, label) pairs. "
"For example: [('blue','Blue'),('yellow','Yellow')]"),
'required': fields.boolean('Required'),
'readonly': fields.boolean('Readonly'),
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
'translate': fields.boolean('Translate'),
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search (deprecated)')],'Searchable', required=True),
'translate': fields.boolean('Translate', help="Whether values for this field can be translated (enables the translation mechanism for that field)"),
'size': fields.integer('Size'),
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
'domain': fields.char('Domain', size=256),
'domain': fields.char('Domain', size=256, help="The optional domain to restrict possible values for relationship fields, "
"specified as a Python expression defining a list of triplets. "
"For example: [('color','=','red')]"),
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
'view_load': fields.boolean('View Auto-Load'),
'selectable': fields.boolean('Selectable'),
@@ -174,7 +184,7 @@ class ir_model_fields(osv.osv):
_rec_name='field_description'
_defaults = {
'view_load': lambda *a: 0,
'selection': lambda *a: "[]",
'selection': lambda *a: "[('key','label')]",
'domain': lambda *a: "[]",
'name': lambda *a: 'x_',
'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
@@ -185,6 +195,25 @@ class ir_model_fields(osv.osv):
'selectable': lambda *a: 1,
}
_order = "name"
def _check_selection(self, cr, uid, ids, context=None):
selection_field = self.browse(cr, uid, ids[0], context=context)
try:
selection_list = eval(selection_field.selection)
except Exception:
logging.getLogger('ir.model').error('Invalid selection list definition for fields.selection %s', selection_field.name , exc_info=True)
return False
if not (isinstance(selection_list, list) and selection_list):
return False
for selection_item in selection_list:
if not (isinstance(selection_item, (tuple,list)) and len(selection_item) == 2):
return False
return True
_constraints = [
(_check_selection, "Wrong list of values specified for a field of type selection, it should be written as [('key','value')]", ['selection'])
]
def _size_gt_zero_msg(self, cr, user, ids, context=None):
return _('Size of the field can never be less than 1 !')
+4 -2
View File
@@ -61,6 +61,10 @@ class ir_translation(osv.osv):
'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16, select=True),
'src': fields.text('Source'),
'value': fields.text('Translation Value'),
# These two columns map to ir_model_data.module and ir_model_data.name.
# They are used to resolve the res_id above after loading is done.
'module': fields.char('Module', size=64, help='Maps to the ir_model_data for which this translation is provided.'),
'xml_id': fields.char('XML Id', size=128, help='Maps to the ir_model_data for which this translation is provided.'),
}
def _auto_init(self, cr, context={}):
@@ -88,8 +92,6 @@ class ir_translation(osv.osv):
cr.execute('CREATE INDEX ir_translation_ltn ON ir_translation (name, lang, type)')
cr.commit()
@tools.cache(skiparg=3, multi='ids')
def _get_ids(self, cr, uid, name, tt, lang, ids):
translations = dict.fromkeys(ids, False)
+9 -7
View File
@@ -257,12 +257,14 @@ class ir_ui_menu(osv.osv):
def read_image(self, path):
path_info = path.split(',')
icon_path = addons.get_module_resource(path_info[0],path_info[1])
icon_file = tools.file_open(icon_path,'rb')
try:
icon = icon_file.read()
return base64.encodestring(icon)
finally:
icon_file.close()
icon_image = False
if icon_path:
try:
icon_file = tools.file_open(icon_path,'rb')
icon_image = base64.encodestring(icon_file.read())
finally:
icon_file.close()
return icon_image
def _get_image_icon(self, cr, uid, ids, name, args, context=None):
res = {}
@@ -304,7 +306,7 @@ class ir_ui_menu(osv.osv):
('ir.actions.server', 'ir.actions.server'),
]),
}
def _rec_message(self, cr, uid, ids, context=None):
return _('Error ! You can not create recursive Menu.')
+7 -33
View File
@@ -95,45 +95,19 @@ class view(osv.osv):
if not cr.fetchone():
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, type, inherit_id)')
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
def write(self, cr, uid, ids, vals, context={}):
if not isinstance(ids, (list, tuple)):
ids = [ids]
result = super(view, self).write(cr, uid, ids, vals, context)
result = super(view, self).read(cr, uid, ids, fields, context, load)
for rs in result:
if rs.get('model') == 'board.board':
cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%s and ref_id=%s", (uid, rs['id']))
oview = cr.dictfetchall()
if oview:
rs['arch'] = oview[0]['arch']
# drop the corresponding view customizations (used for dashboards for example), otherwise
# not all users would see the updated views
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
if custom_view_ids:
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
return result
def write(self, cr, uid, ids, vals, context={}):
if not isinstance(ids, (list, tuple)):
ids = [ids]
exist = self.pool.get('ir.ui.view').browse(cr, uid, ids[0])
if exist.model == 'board.board' and 'arch' in vals:
vids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('user_id','=',uid), ('ref_id','=',ids[0])])
vals2 = {'user_id': uid, 'ref_id': ids[0], 'arch': vals.pop('arch')}
# write fields except arch to the `ir.ui.view`
result = super(view, self).write(cr, uid, ids, vals, context)
if not vids:
self.pool.get('ir.ui.view.custom').create(cr, uid, vals2)
else:
self.pool.get('ir.ui.view.custom').write(cr, uid, vids, vals2)
return result
return super(view, self).write(cr, uid, ids, vals, context)
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node,label,scale,context={}):
if not label:
label = []
+3 -2
View File
@@ -501,7 +501,7 @@ class module(osv.osv):
f2 = addons.get_module_resource(mod.name, 'i18n', iso_lang2 + '.po')
if f2:
logger.info('module %s: loading base translation file %s for language %s', mod.name, iso_lang2, lang)
tools.trans_load(cr.dbname, f2, lang, verbose=False, context=context)
tools.trans_load(cr, f2, lang, verbose=False, context=context)
context2['overwrite'] = True
# Implementation notice: we must first search for the full name of
# the language derivative, like "en_UK", and then the generic,
@@ -511,9 +511,10 @@ class module(osv.osv):
f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po')
if f:
logger.info('module %s: loading translation file (%s) for language %s', mod.name, iso_lang, lang)
tools.trans_load(cr.dbname, f, lang, verbose=False, context=context2)
tools.trans_load(cr, f, lang, verbose=False, context=context2)
elif iso_lang != 'en':
logger.warning('module %s: no translation for language %s', mod.name, iso_lang)
tools.trans_update_res_ids(cr)
def check(self, cr, uid, ids, context=None):
logger = logging.getLogger('init')
@@ -56,8 +56,9 @@ class base_language_import(osv.osv_memory):
fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po'
fileobj.seek(0)
tools.trans_load_data(cr.dbname, fileobj, fileformat, import_data.code, lang_name=import_data.name)
tools.trans_load_data(cr, fileobj, fileformat, import_data.code, lang_name=import_data.name)
tools.trans_update_res_ids(cr)
fileobj.close()
return {}
base_language_import()
base_language_import()
@@ -45,8 +45,9 @@ class base_update_translations(osv.osv_memory):
this = self.browse(cr, uid, ids)[0]
lang_name = self._get_lang_name(cr, uid, this.lang)
buf=cStringIO.StringIO()
tools.trans_export(this.lang, ['all'], buf, 'csv', dbname=cr.dbname)
tools.trans_load_data(cr.dbname, buf, 'csv', this.lang, lang_name=lang_name)
tools.trans_export(this.lang, ['all'], buf, 'csv', cr)
tools.trans_load_data(cr, buf, 'csv', this.lang, lang_name=lang_name)
tools.trans_update_res_ids(cr)
buf.close()
return {'type': 'ir.actions.act_window_close'}
@@ -70,4 +71,4 @@ class base_update_translations(osv.osv_memory):
'lang': fields.selection(_get_languages, 'Language', required=True),
}
base_update_translations()
base_update_translations()
+1 -1
View File
@@ -138,7 +138,7 @@ class res_partner(osv.osv):
'email': fields.related('address', 'email', type='char', size=240, string='E-mail'),
'company_id': fields.many2one('res.company', 'Company', select=1),
}
def _default_category(self, cr, uid, context={}):
if 'category_id' in context and context['category_id']:
return [context['category_id']]
+64 -5
View File
@@ -24,10 +24,69 @@ from locale import localeconv
import tools
from tools.safe_eval import safe_eval as eval
from tools.translate import _
import locale
import logging
class lang(osv.osv):
_name = "res.lang"
_description = "Languages"
def install_lang(self, cr, uid, **args):
lang = tools.config.get('lang')
if not lang:
return False
lang_ids = self.search(cr, uid, [('code','=', lang)])
values_obj = self.pool.get('ir.values')
if not lang_ids:
lang_id = self.load_lang(cr, uid, lang)
default_value = values_obj.get(cr, uid, 'default', False, 'res.partner')
if not default_value:
values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], lang)
return True
def load_lang(self, cr, uid, lang, lang_name=None):
# create the language with locale information
fail = True
logger = logging.getLogger('i18n')
iso_lang = tools.get_iso_codes(lang)
for ln in tools.get_locales(lang):
try:
locale.setlocale(locale.LC_ALL, str(ln))
fail = False
break
except locale.Error:
continue
if fail:
lc = locale.getdefaultlocale()[0]
msg = 'Unable to get information for locale %s. Information from the default locale (%s) have been used.'
logger.warning(msg, lang, lc)
if not lang_name:
lang_name = tools.get_languages().get(lang, lang)
def fix_xa0(s):
if s == '\xa0':
return '\xc2\xa0'
return s
lang_info = {
'code': lang,
'iso_code': iso_lang,
'name': lang_name,
'translatable': 1,
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
}
lang_id = False
try:
lang_id = self.create(cr, uid, lang_info)
finally:
tools.resetlocale()
return lang_id
def _get_default_date_format(self,cursor,user,context={}):
return '%m/%d/%Y'
@@ -69,7 +128,7 @@ class lang(osv.osv):
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
decimal_point = lang_obj.decimal_point
grouping = lang_obj.grouping
return (grouping, thousands_sep, decimal_point)
return (grouping, thousands_sep, decimal_point)
def write(self, cr, uid, ids, vals, context=None):
for lang_id in ids :
@@ -95,19 +154,19 @@ class lang(osv.osv):
def _group(self, cr, uid, ids, s, monetary=False, grouping=False, thousands_sep=''):
grouping = eval(grouping)
if not grouping:
return (s, 0)
result = ""
seps = 0
spaces = ""
if s[-1] == ' ':
sp = s.find(' ')
spaces = s[sp:]
s = s[:sp]
while s and grouping:
# if grouping is -1, we are done
if grouping[0] == -1:
@@ -139,7 +198,7 @@ class lang(osv.osv):
if percent[0] != '%':
raise ValueError("format() must be given exactly one %char format specifier")
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
formatted = percent % value
# floats and decimal ints need special action!
+31 -36
View File
@@ -194,6 +194,18 @@ class users(osv.osv):
self.write(cr, uid, ids, {'address_id': address_id}, context)
return True
def _set_new_password(self, cr, uid, id, name, value, args, context=None):
if value is False:
# Do not update the password if no value is provided, ignore silently.
# For example web client submits False values for all empty fields.
return
if uid == id:
# To change their own password users must use the client-specific change password wizard,
# so that the new password is immediately used for further RPC requests, otherwise the user
# will face unexpected 'Access Denied' exceptions.
raise osv.except_osv(_('Operation Canceled'), _('Please use the change password wizard (in User Preferences or User menu) to change your own password.'))
self.write(cr, uid, id, {'password': value})
_columns = {
'name': fields.char('User Name', size=64, required=True, select=True,
help="The new user's real name, used for searching"
@@ -201,6 +213,10 @@ class users(osv.osv):
'login': fields.char('Login', size=64, required=True,
help="Used to log into the system"),
'password': fields.char('Password', size=64, invisible=True, help="Keep empty if you don't want the user to be able to connect on the system."),
'new_password': fields.function(lambda *a:'', method=True, type='char', size=64,
fnct_inv=_set_new_password,
string='Change password', help="Only specify a value if you want to change the user password. "
"This user will have to logout and login again!"),
'email': fields.char('E-mail', size=64,
help='If an email is provided, the user will be sent a message '
'welcoming him.\n\nWarning: if "email_from" and "smtp_server"'
@@ -476,6 +492,20 @@ class users(osv.osv):
finally:
cr.close()
def change_password(self, cr, uid, old_passwd, new_passwd, context=None):
"""Change current user password. Old password must be provided explicitly
to prevent hijacking an existing user session, or for cases where the cleartext
password is not used to authenticate requests.
:return: True
:raise: security.ExceptionNoTb when old password is wrong
:raise: except_osv when new password is not set or empty
"""
self.check(cr.dbname, uid, old_passwd)
if new_passwd:
return self.write(cr, uid, uid, {'password': new_passwd})
raise osv.except_osv(_('Warning!'), _("Setting empty passwords is not allowed for security reasons!"))
users()
class config_users(osv.osv_memory):
@@ -574,39 +604,4 @@ class res_config_view(osv.osv_memory):
res_config_view()
class change_user_password(osv.osv_memory):
_name = 'change.user.password'
_columns = {
'current_password':fields.char('Current Password', size=64, required=True, help="Enter your current password."),
'new_password': fields.char('New Password', size=64, required=True, help="Enter the new password."),
'confirm_password': fields.char('Confirm Password', size=64, required=True, help="Enter the new password again for confirmation."),
}
_defaults={
'current_password' : '',
'new_password' : '',
'confirm_password' : '',
}
def change_password(self, cr, uid, ids, context=None):
for form_id in ids:
password_rec = self.browse(cr, uid, form_id, context)
if password_rec.new_password != password_rec.confirm_password:
raise osv.except_osv(_('Error !'), _('The new and confirmation passwords do not match, please double-check them.'))
# Validate current password without reading it from database,
# as it could be stored differently (LDAP, encrypted/hashed, etc.)
is_correct_password = False
try:
user_obj = self.pool.get('res.users')
is_correct_password = user_obj.check(cr.dbname, uid, password_rec.current_password)
except Exception:
pass
if not is_correct_password:
raise osv.except_osv(_('Error !'), _('The current password does not match, please double-check it.'))
user_obj.write(cr, uid, [uid], {'password': password_rec.new_password}, context=context)
return {}
change_user_password()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+4 -4
View File
@@ -473,10 +473,10 @@ def replace_request_password(args):
return args
class OpenERPDispatcher:
def log(self, title, msg, channel=logging.DEBUG_RPC, depth=2):
def log(self, title, msg, channel=logging.DEBUG_RPC, depth=None):
logger = logging.getLogger(title)
if logger.isEnabledFor(channel):
for line in pformat(msg, depth=100).split('\n'):
for line in pformat(msg, depth=depth).split('\n'):
logger.log(channel, line)
def dispatch(self, service_name, method, params):
@@ -484,10 +484,10 @@ class OpenERPDispatcher:
logger = logging.getLogger('result')
self.log('service', service_name)
self.log('method', method)
self.log('params', replace_request_password(params), depth=(logger.isEnabledFor(logging.DEBUG_RPC_ANSWER) and 3 or 1))
self.log('params', replace_request_password(params), depth=(None if logger.isEnabledFor(logging.DEBUG_RPC_ANSWER) else 1))
auth = getattr(self, 'auth_provider', None)
result = ExportService.getService(service_name).dispatch(method, auth, params)
self.log('result', result, channel=logging.DEBUG_RPC_ANSWER, depth=(logger.isEnabledFor(logging.DEBUG_SQL) and 5 or 3))
self.log('result', result, channel=logging.DEBUG_RPC_ANSWER)
return result
except Exception, e:
self.log('exception', tools.exception_to_unicode(e))
+10 -2
View File
@@ -144,7 +144,10 @@ if tools.config["translate_out"]:
fileformat = os.path.splitext(tools.config["translate_out"])[-1][1:].lower()
buf = file(tools.config["translate_out"], "w")
tools.trans_export(tools.config["language"], tools.config["translate_modules"], buf, fileformat)
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_export(tools.config["language"], tools.config["translate_modules"] or ["all"], buf, fileformat, cr)
cr.close()
buf.close()
logger.info('translation file written successfully')
@@ -152,10 +155,15 @@ if tools.config["translate_out"]:
if tools.config["translate_in"]:
context = {'overwrite': tools.config["overwrite_existing_translations"]}
tools.trans_load(tools.config["db_name"],
dbname = tools.config['db_name']
cr = pooler.get_db(dbname).cursor()
tools.trans_load(cr,
tools.config["translate_in"],
tools.config["language"],
context=context)
tools.trans_update_res_ids(cr)
cr.commit()
cr.close()
sys.exit(0)
#----------------------------------------------------------------------------------
+3 -2
View File
@@ -553,7 +553,7 @@ class many2many(_column):
DeprecationWarning, stacklevel=2)
obj = obj.pool.get(self._obj)
# static domains are lists, and are evaluated both here and on client-side, while string
# static domains are lists, and are evaluated both here and on client-side, while string
# domains supposed by dynamic and evaluated on client-side only (thus ignored here)
# FIXME: make this distinction explicit in API!
domain = isinstance(self._domain, list) and self._domain or []
@@ -1049,7 +1049,8 @@ class property(function):
brs = properties.browse(cr, uid, nids, context=context)
for prop in brs:
value = properties.get_by_record(cr, uid, prop, context=context)
res[prop.res_id.id][prop.fields_id.name] = value or False
record_exists = obj.pool.get(value._name).exists(cr, uid, value.id)
res[prop.res_id.id][prop.fields_id.name] = (record_exists and value) and value or False
if value and (prop.type == 'many2one'):
replaces.setdefault(value._name, {})
replaces[value._name][value.id] = True
+12 -11
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -50,8 +50,8 @@ class db(netsvc.ExportService):
self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var
def dispatch(self, method, auth, params):
if method in [ 'create', 'get_progress', 'drop', 'dump',
'restore', 'rename',
if method in [ 'create', 'get_progress', 'drop', 'dump',
'restore', 'rename',
'change_admin_password', 'migrate_databases' ]:
passwd = params[0]
params = params[1:]
@@ -64,7 +64,7 @@ class db(netsvc.ExportService):
raise KeyError("Method not found: %s" % method)
fn = getattr(self, 'exp_'+method)
return fn(*params)
def new_dispatch(self,method,auth,params):
pass
def _create_empty_database(self, name):
@@ -93,6 +93,7 @@ class db(netsvc.ExportService):
serv.actions[id]['progress'] = 0
cr = sql_db.db_connect(db_name).cursor()
tools.init_db(cr)
tools.config['lang'] = lang
cr.commit()
cr.close()
cr = None
@@ -392,7 +393,7 @@ class common(_ObjectService):
security.check_super(passwd)
else:
raise Exception("Method not found: %s" % method)
fn = getattr(self, 'exp_'+method)
return fn(*params)
@@ -568,7 +569,7 @@ GNU Public Licence.
def exp_check_connectivity(self):
return bool(sql_db.db_connect('template1'))
def exp_get_os_time(self):
return os.times()
@@ -598,7 +599,7 @@ class objects_proxy(netsvc.ExportService):
res = fn(db, uid, *params)
return res
def new_dispatch(self,method,auth,params):
pass
@@ -634,7 +635,7 @@ class wizard(netsvc.ExportService):
fn = getattr(self, 'exp_'+method)
res = fn(db, uid, *params)
return res
def new_dispatch(self,method,auth,params):
pass
@@ -697,7 +698,7 @@ class report_spool(netsvc.ExportService):
res = fn(db, uid, *params)
return res
def new_dispatch(self,method,auth,params):
pass
@@ -728,7 +729,7 @@ class report_spool(netsvc.ExportService):
self._reports[id]['format'] = format
self._reports[id]['state'] = True
except Exception, exception:
tb = sys.exc_info()
tb_s = "".join(traceback.format_exception(*tb))
logger = netsvc.Logger()
+34 -65
View File
@@ -347,7 +347,7 @@ class TinyPoFile(object):
if name is None:
if not fuzzy:
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
self.cur_line(), source[:30])
return self.next()
return type, name, res_id, source, trad
@@ -409,7 +409,7 @@ class TinyPoFile(object):
# Methods to export the translation file
def trans_export(lang, modules, buffer, format, dbname=None):
def trans_export(lang, modules, buffer, format, cr):
def _process(format, modules, rows, buffer, lang, newlang):
if format == 'csv':
@@ -461,7 +461,7 @@ def trans_export(lang, modules, buffer, format, dbname=None):
newlang = not bool(lang)
if newlang:
lang = 'en_US'
trans = trans_generate(lang, modules, dbname)
trans = trans_generate(lang, modules, cr)
if newlang and format!='csv':
for trx in trans:
trx[-1] = ''
@@ -524,26 +524,22 @@ def in_modules(object_name, modules):
module = module_dict.get(module, module)
return module in modules
def trans_generate(lang, modules, dbname=None):
def trans_generate(lang, modules, cr):
logger = logging.getLogger('i18n')
if not dbname:
dbname=tools.config['db_name']
if not modules:
modules = ['all']
dbname = cr.dbname
pool = pooler.get_pool(dbname)
trans_obj = pool.get('ir.translation')
model_data_obj = pool.get('ir.model.data')
cr = pooler.get_db(dbname).cursor()
uid = 1
l = pool.obj_pool.items()
l.sort()
query = 'SELECT name, model, res_id, module' \
' FROM ir_model_data'
query_models = """SELECT m.id, m.model, imd.module
FROM ir_model AS m, ir_model_data AS imd
query_models = """SELECT m.id, m.model, imd.module
FROM ir_model AS m, ir_model_data AS imd
WHERE m.id = imd.res_id AND imd.model = 'ir.model' """
if 'all_installed' in modules:
@@ -834,16 +830,15 @@ def trans_generate(lang, modules, dbname=None):
trans = trans_obj._get_source(cr, uid, name, type, lang, source)
out.append([module, type, name, id, source, encode(trans) or ''])
cr.close()
return out
def trans_load(db_name, filename, lang, verbose=True, context=None):
def trans_load(cr, filename, lang, verbose=True, context=None):
logger = logging.getLogger('i18n')
try:
fileobj = open(filename,'r')
logger.info("loading %s", filename)
fileformat = os.path.splitext(filename)[-1][1:].lower()
r = trans_load_data(db_name, fileobj, fileformat, lang, verbose=verbose, context=context)
r = trans_load_data(cr, fileobj, fileformat, lang, verbose=verbose, context=context)
fileobj.close()
return r
except IOError:
@@ -851,12 +846,16 @@ def trans_load(db_name, filename, lang, verbose=True, context=None):
logger.error("couldn't read translation file %s", filename)
return None
def trans_load_data(db_name, fileobj, fileformat, lang, lang_name=None, verbose=True, context=None):
def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, context=None):
"""Populates the ir_translation table. Fixing the res_ids so that they point
correctly to ir_model_data is done in a separate step, using the
'trans_update_res_ids' function below."""
logger = logging.getLogger('i18n')
if verbose:
logger.info('loading translation file for language %s', lang)
if context is None:
context = {}
db_name = cr.dbname
pool = pooler.get_pool(db_name)
lang_obj = pool.get('res.lang')
trans_obj = pool.get('ir.translation')
@@ -864,47 +863,11 @@ def trans_load_data(db_name, fileobj, fileformat, lang, lang_name=None, verbose=
iso_lang = tools.get_iso_codes(lang)
try:
uid = 1
cr = pooler.get_db(db_name).cursor()
ids = lang_obj.search(cr, uid, [('code','=', lang)])
if not ids:
# lets create the language with locale information
fail = True
for ln in get_locales(lang):
try:
locale.setlocale(locale.LC_ALL, str(ln))
fail = False
break
except locale.Error:
continue
if fail:
lc = locale.getdefaultlocale()[0]
msg = 'Unable to get information for locale %s. Information from the default locale (%s) have been used.'
logger.warning(msg, lang, lc)
if not lang_name:
lang_name = tools.get_languages().get(lang, lang)
def fix_xa0(s):
if s == '\xa0':
return '\xc2\xa0'
return s
lang_info = {
'code': lang,
'iso_code': iso_lang,
'name': lang_name,
'translatable': 1,
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
}
try:
lang_obj.create(cr, uid, lang_info)
finally:
resetlocale()
lang_obj.load_lang(cr, 1, lang=lang, lang_name=lang_name)
# now, the serious things: we read the language file
@@ -941,17 +904,13 @@ def trans_load_data(db_name, fileobj, fileformat, lang, lang_name=None, verbose=
try:
dic['res_id'] = dic['res_id'] and int(dic['res_id']) or 0
dic['module'] = False
dic['xml_id'] = False
except:
model_data_ids = model_data_obj.search(cr, uid, [
('model', '=', dic['name'].split(',')[0]),
('module', '=', dic['res_id'].split('.', 1)[0]),
('name', '=', dic['res_id'].split('.', 1)[1]),
])
if model_data_ids:
dic['res_id'] = model_data_obj.browse(cr, uid,
model_data_ids[0]).res_id
else:
dic['res_id'] = False
split_id = dic['res_id'].split('.', 1)
dic['module'] = split_id[0]
dic['xml_id'] = split_id[1]
dic['res_id'] = False
args = [
('lang', '=', lang),
@@ -967,14 +926,24 @@ def trans_load_data(db_name, fileobj, fileformat, lang, lang_name=None, verbose=
trans_obj.write(cr, uid, ids, {'value': dic['value']})
else:
trans_obj.create(cr, uid, dic)
cr.commit()
cr.close()
if verbose:
logger.info("translation file loaded succesfully")
except IOError:
filename = '[lang: %s][format: %s]' % (iso_lang or 'new', fileformat)
logger.exception("couldn't read translation file %s", filename)
def trans_update_res_ids(cr):
cr.execute("""
UPDATE ir_translation
SET res_id = (SELECT ir_model_data.res_id
FROM ir_model_data
WHERE ir_translation.module = ir_model_data.module
AND ir_translation.xml_id = ir_model_data.name)
WHERE ir_translation.module is not null
AND ir_translation.xml_id is not null
AND ir_translation.res_id = 0;
""")
def get_locales(lang=None):
if lang is None:
lang = locale.getdefaultlocale()[0]