merge
This commit is contained in:
commit
4e28287941
14 files changed
+142
-53
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Add replace_attributes for xpath tag
|
||||
* Add email paramter on report action
|
||||
* Allow to inherit views from an other model
|
||||
* Add user warnings
|
||||
|
||||
+1
-1
@@ -430,7 +430,7 @@ xpath
|
||||
|
||||
* ``expr``: the xpath expression to find a node in the inherited view.
|
||||
|
||||
* ``position``: Define the position from the finded node, it can be ``before``, ``after``, ``replace``, ``inside``.
|
||||
* ``position``: Define the position from the finded node, it can be ``before``, ``after``, ``replace``, ``inside`` or ``replace_attributes`` which will change the attributes.
|
||||
|
||||
Example
|
||||
+++++++
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"Action"
|
||||
from trytond.osv import fields, OSV
|
||||
from trytond.tools import file_open
|
||||
from trytond.sql_db import table_handler
|
||||
|
||||
|
||||
class Action(OSV):
|
||||
@@ -411,6 +412,15 @@ class ActionActWindowView(OSV):
|
||||
super(ActionActWindowView, self).__init__()
|
||||
self._order.insert(0, ('sequence', 'ASC'))
|
||||
|
||||
def _auto_init(self, cursor, module_name):
|
||||
super(ActionActWindowView, self)._auto_init(cursor, module_name)
|
||||
table = table_handler(cursor, self._table, self._name, module_name)
|
||||
|
||||
# Migration from 1.0 remove multi
|
||||
if 'multi' in table.table:
|
||||
cursor.execute('ALTER TABLE "' + self._table + '" ' \
|
||||
'DROP COLUMN multi')
|
||||
|
||||
ActionActWindowView()
|
||||
|
||||
|
||||
|
||||
@@ -149,12 +149,14 @@ xpath = element xpath { attlist.xpath,
|
||||
| action
|
||||
| page
|
||||
| child1
|
||||
| child2)*
|
||||
| child2
|
||||
| board
|
||||
)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "after" | "before" }?
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
action |= notAllowed
|
||||
label |= notAllowed
|
||||
start = data | board | label
|
||||
@@ -442,6 +442,7 @@
|
||||
<ref name="page"/>
|
||||
<ref name="child1"/>
|
||||
<ref name="child2"/>
|
||||
<ref name="board"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
@@ -455,6 +456,7 @@
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
|
||||
@@ -272,6 +272,6 @@ xpath = element xpath { attlist.xpath,
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "after" | "before" }?
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
|
||||
start = data | form
|
||||
@@ -865,6 +865,7 @@
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
|
||||
@@ -34,5 +34,5 @@ xpath = element xpath { attlist.xpath,
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "after" | "before" }?
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
start = data | graph
|
||||
@@ -152,6 +152,7 @@
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
|
||||
@@ -67,10 +67,11 @@ attlist.data &= empty
|
||||
xpath = element xpath { attlist.xpath,
|
||||
(field
|
||||
| button
|
||||
| tree
|
||||
)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "after" | "before" }?
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
start = tree | data
|
||||
@@ -211,6 +211,7 @@
|
||||
<choice>
|
||||
<ref name="field"/>
|
||||
<ref name="button"/>
|
||||
<ref name="tree"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
@@ -224,6 +225,7 @@
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
|
||||
@@ -2224,6 +2224,10 @@ class ORM(object):
|
||||
else:
|
||||
parent.extend(element2.getchildren())
|
||||
parent.remove(element)
|
||||
elif pos == 'replace_attributes':
|
||||
child = element2.getchildren()[0]
|
||||
for attr in child.attrib:
|
||||
element.set(attr, child.get(attr))
|
||||
elif pos == 'inside':
|
||||
element.extend(element2.getchildren())
|
||||
elif pos == 'after':
|
||||
|
||||
+109
-45
@@ -291,18 +291,28 @@ class Fs2bdAccessor:
|
||||
Provide some helper function to ease cache access and management.
|
||||
"""
|
||||
|
||||
def __init__(self, cursor, user, modeldata_obj):
|
||||
def __init__(self, cursor, user, modeldata_obj, pool):
|
||||
self.fs2db = {}
|
||||
self.fetched_modules = []
|
||||
self.modeldata_obj = modeldata_obj
|
||||
self.cursor = cursor
|
||||
self.user = user
|
||||
self.browserecord = {}
|
||||
self.pool = pool
|
||||
|
||||
def get(self, module, fs_id):
|
||||
if module not in self.fetched_modules:
|
||||
self.fetch_new_module(module)
|
||||
return self.fs2db[module].get(fs_id, None)
|
||||
|
||||
def get_browserecord(self, module, model_name, db_id):
|
||||
if module not in self.fetched_modules:
|
||||
self.fetch_new_module(module)
|
||||
if model_name in self.browserecord[module] \
|
||||
and db_id in self.browserecord[module][model_name]:
|
||||
return self.browserecord[module][model_name][db_id]
|
||||
return None
|
||||
|
||||
def set(self, module, fs_id, values):
|
||||
"""
|
||||
Whe call the prefetch function here to. Like that whe are sure
|
||||
@@ -316,6 +326,23 @@ class Fs2bdAccessor:
|
||||
for key, val in values.items():
|
||||
fs2db_val[key] = val
|
||||
|
||||
def reset_browsercord(self, module, model_name, ids=None):
|
||||
if module not in self.fetched_modules:
|
||||
return
|
||||
if model_name not in self.browserecord[module]:
|
||||
return
|
||||
model_obj = self.pool.get(model_name)
|
||||
if not ids:
|
||||
object_ids = self.browserecord[module][model_name].keys()
|
||||
else:
|
||||
if isinstance(ids, (int, long)):
|
||||
object_ids = [ids]
|
||||
else:
|
||||
object_ids = ids
|
||||
models = model_obj.browse(self.cursor, self.user, object_ids)
|
||||
for model in models:
|
||||
self.browserecord[module][model_name][model.id] = model
|
||||
|
||||
def fetch_new_module(self, module):
|
||||
if module == "ir.ui.menu": raise
|
||||
self.fs2db[module] = {}
|
||||
@@ -324,12 +351,27 @@ class Fs2bdAccessor:
|
||||
('module', '=', module),
|
||||
('inherit', '=', False),
|
||||
])
|
||||
|
||||
record_ids = {}
|
||||
for rec in self.modeldata_obj.browse(
|
||||
self.cursor, self.user, module_data_ids):
|
||||
self.fs2db[rec.module][rec.fs_id] = {
|
||||
"db_id": rec.db_id, "model": rec.model,
|
||||
"id": rec.id, "values": rec.values
|
||||
}
|
||||
record_ids.setdefault(rec.model, [])
|
||||
record_ids[rec.model].append(rec.db_id)
|
||||
|
||||
self.browserecord[module] = {}
|
||||
for model_name in record_ids.keys():
|
||||
model_obj = self.pool.get(model_name)
|
||||
self.browserecord[module][model_name] = {}
|
||||
ids = model_obj.search(self.cursor, self.user, [
|
||||
('id', 'in', record_ids[model_name]),
|
||||
], context={'active_test': False})
|
||||
models = model_obj.browse(self.cursor, self.user, ids)
|
||||
for model in models:
|
||||
self.browserecord[module][model_name][model.id] = model
|
||||
self.fetched_modules.append(module)
|
||||
|
||||
|
||||
@@ -343,7 +385,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
self.user = 0
|
||||
self.module = module
|
||||
self.modeldata_obj = pool.get('ir.model.data')
|
||||
self.fs2db = Fs2bdAccessor(cursor, self.user, self.modeldata_obj)
|
||||
self.fs2db = Fs2bdAccessor(cursor, self.user, self.modeldata_obj, pool)
|
||||
self.to_delete = self.populate_to_delete()
|
||||
|
||||
# Tag handlders are used to delegate the processing
|
||||
@@ -541,8 +583,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
"data with the wrong model: %s (module: %s)" % (fs_id, module))
|
||||
|
||||
#Re-create object if it was deleted
|
||||
if not object_ref.search(cursor, user, [('id', '=', db_id)],
|
||||
context={'active_test': False}):
|
||||
if not self.fs2db.get_browserecord(module, object_ref._name, db_id):
|
||||
db_id = object_ref.create(cursor, user, values,
|
||||
context={'module': module})
|
||||
|
||||
@@ -563,13 +604,28 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
object_ref._inherit_fields[field_name][0])._name
|
||||
res_id = inherit_db_ids[table_name]
|
||||
if field.translate and values.get(field_name):
|
||||
cursor.execute('INSERT INTO ir_translation ' \
|
||||
'(name, lang, type, src, res_id, ' \
|
||||
'value, module, fuzzy) ' \
|
||||
'VALUES (%s, %s, %s, %s, %s, %s, %s, false)',
|
||||
cursor.execute('SELECT id FROM ir_translation ' \
|
||||
'WHERE name = %s ' \
|
||||
'AND lang = %s ' \
|
||||
'AND type = %s ' \
|
||||
'AND res_id = %s ' \
|
||||
'AND module = %s',
|
||||
(table_name + ',' + field_name,
|
||||
'en_US', 'model', values[field_name],
|
||||
res_id, '', module))
|
||||
'en_US', 'model', res_id, module))
|
||||
if cursor.rowcount:
|
||||
trans_id = cursor.fetchone()[0]
|
||||
cursor.execute('UPDATE ir_translation ' \
|
||||
'SET src = %s, module = %s ' \
|
||||
'WHERE id = %s',
|
||||
(values[field_name], module, trans_id))
|
||||
else:
|
||||
cursor.execute('INSERT INTO ir_translation ' \
|
||||
'(name, lang, type, src, res_id, ' \
|
||||
'value, module, fuzzy) ' \
|
||||
'VALUES (%s, %s, %s, %s, %s, %s, %s, false)',
|
||||
(table_name + ',' + field_name,
|
||||
'en_US', 'model', values[field_name],
|
||||
res_id, '', module))
|
||||
|
||||
for table in inherit_db_ids.keys():
|
||||
data_id = self.modeldata_obj.search(cursor, user, [
|
||||
@@ -602,7 +658,9 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
})
|
||||
self.fs2db.get(module, fs_id)["db_id"] = db_id
|
||||
|
||||
db_val = object_ref.browse(cursor, user, db_id)
|
||||
db_val = self.fs2db.get_browserecord(module, object_ref._name, db_id)
|
||||
if not db_val:
|
||||
db_val = object_ref.browse(cursor, user, db_id)
|
||||
|
||||
to_update = {}
|
||||
for key in values:
|
||||
@@ -650,6 +708,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
# write the values in the db:
|
||||
object_ref.write(cursor, user, db_id, to_update,
|
||||
context={'module': module})
|
||||
self.fs2db.reset_browsercord(module, object_ref._name, db_id)
|
||||
|
||||
|
||||
if not inherit_db_ids:
|
||||
@@ -667,45 +726,50 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
|
||||
inherit_mdata_ids.append((table, data_id))
|
||||
|
||||
#Update/Create translation record for field translatable
|
||||
for field_name in object_ref._columns.keys() + \
|
||||
object_ref._inherit_fields.keys():
|
||||
if field_name in object_ref._columns:
|
||||
field = object_ref._columns[field_name]
|
||||
table_name = object_ref._name
|
||||
res_id = db_id
|
||||
else:
|
||||
field = object_ref._inherit_fields[field_name][2]
|
||||
table_name = self.pool.get(
|
||||
object_ref._inherit_fields[field_name][0])._name
|
||||
res_id = inherit_db_ids[table_name]
|
||||
if field.translate:
|
||||
cursor.execute('SELECT id FROM ir_translation ' \
|
||||
'WHERE name = %s' \
|
||||
'AND lang = %s ' \
|
||||
'AND type = %s ' \
|
||||
'AND res_id = %s',
|
||||
(table_name + ',' + field_name,
|
||||
'en_US', 'model', res_id))
|
||||
if cursor.rowcount:
|
||||
if to_update.get(field_name):
|
||||
trans_id = cursor.fetchone()[0]
|
||||
cursor.execute('UPDATE ir_translation ' \
|
||||
'SET src = %s, module = %s ' \
|
||||
'WHERE id = %s',
|
||||
(to_update[field_name], module, trans_id))
|
||||
elif values.get(field_name):
|
||||
cursor.execute('INSERT INTO ir_translation ' \
|
||||
'(name, lang, type, src, res_id, ' \
|
||||
'value, module, fuzzy) ' \
|
||||
'VALUES (%s, %s, %s, %s, %s, %s, %s, false)',
|
||||
if to_update:
|
||||
for field_name in object_ref._columns.keys() + \
|
||||
object_ref._inherit_fields.keys():
|
||||
if field_name in object_ref._columns:
|
||||
field = object_ref._columns[field_name]
|
||||
table_name = object_ref._name
|
||||
res_id = db_id
|
||||
else:
|
||||
field = object_ref._inherit_fields[field_name][2]
|
||||
table_name = self.pool.get(
|
||||
object_ref._inherit_fields[field_name][0])._name
|
||||
res_id = inherit_db_ids[table_name]
|
||||
if field.translate:
|
||||
cursor.execute('SELECT id FROM ir_translation ' \
|
||||
'WHERE name = %s ' \
|
||||
'AND lang = %s ' \
|
||||
'AND type = %s ' \
|
||||
'AND res_id = %s ' \
|
||||
'AND module = %s',
|
||||
(table_name + ',' + field_name,
|
||||
'en_US', 'model', values[field_name],
|
||||
res_id, '', module))
|
||||
'en_US', 'model', res_id, module))
|
||||
if cursor.rowcount:
|
||||
if to_update.get(field_name):
|
||||
trans_id = cursor.fetchone()[0]
|
||||
cursor.execute('UPDATE ir_translation ' \
|
||||
'SET src = %s, module = %s ' \
|
||||
'WHERE id = %s',
|
||||
(to_update[field_name], module, trans_id))
|
||||
elif values.get(field_name):
|
||||
cursor.execute('INSERT INTO ir_translation ' \
|
||||
'(name, lang, type, src, res_id, ' \
|
||||
'value, module, fuzzy) ' \
|
||||
'VALUES (%s, %s, %s, %s, %s, %s, %s, false)',
|
||||
(table_name + ',' + field_name,
|
||||
'en_US', 'model', values[field_name],
|
||||
res_id, '', module))
|
||||
|
||||
if to_update:
|
||||
# re-read it: this ensure that we store the real value
|
||||
# in the model_data table:
|
||||
db_val = object_ref.browse(cursor, user, db_id)
|
||||
db_val = self.fs2db.get_browserecord(module, object_ref._name,
|
||||
db_id)
|
||||
if not db_val:
|
||||
db_val = object_ref.browse(cursor, user, db_id)
|
||||
for key in to_update:
|
||||
try:
|
||||
values[key] = self._clean_value(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms.
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Miscelleanous tools used by tryton
|
||||
@@ -27,7 +28,7 @@ def find_in_path(name):
|
||||
val = os.path.join(directory, name)
|
||||
if os.path.isfile(val) or os.path.islink(val):
|
||||
return val
|
||||
return None
|
||||
return name
|
||||
|
||||
def find_pg_tool(name):
|
||||
if CONFIG['pg_path'] and CONFIG['pg_path'] != 'None':
|
||||
|
||||
Reference in new issue
Block a user