diff --git a/trytond/ir/action.py b/trytond/ir/action.py
index 11c762b9e7..9ed2402d77 100644
--- a/trytond/ir/action.py
+++ b/trytond/ir/action.py
@@ -85,7 +85,7 @@ class ActionKeyword(OSV):
res.append([model.model, model.name])
return res
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
for keyword in self.browse(cursor, user, ids, context=context):
@@ -95,7 +95,7 @@ class ActionKeyword(OSV):
.fields_view_get(cursor.dbname)
except:
pass
- return super(ActionKeyword, self).unlink(cursor, user, ids,
+ return super(ActionKeyword, self).delete(cursor, user, ids,
context=context)
def create(self, cursor, user, vals, context=None):
diff --git a/trytond/ir/default.py b/trytond/ir/default.py
index 062bab33e2..b6a7904862 100644
--- a/trytond/ir/default.py
+++ b/trytond/ir/default.py
@@ -67,7 +67,7 @@ class Default(OSV):
('user', '=', user_default),
], context=context)
if default_ids:
- self.unlink(cursor, user, default_ids, context=context)
+ self.delete(cursor, user, default_ids, context=context)
self.create(cursor, user, {
'model': model_id,
'field': field_id,
diff --git a/trytond/ir/model.py b/trytond/ir/model.py
index c3db8ae072..0de22fafba 100644
--- a/trytond/ir/model.py
+++ b/trytond/ir/model.py
@@ -67,7 +67,7 @@ class ModelAccess(OSV):
perm_read = fields.Boolean('Read Access')
perm_write = fields.Boolean('Write Access')
perm_create = fields.Boolean('Create Access')
- perm_unlink = fields.Boolean('Delete Permission')
+ perm_delete = fields.Boolean('Delete Permission')
description = fields.Text('Description')
def __init__(self):
@@ -80,12 +80,12 @@ class ModelAccess(OSV):
'read': 'You can not read this document! (%s)',
'write': 'You can not write in this document! (%s)',
'create': 'You can not create this kind of document! (%s)',
- 'unlink': 'You can not delete this document! (%s)',
+ 'delete': 'You can not delete this document! (%s)',
})
def check(self, cursor, user, model_name, mode='read',
raise_exception=True, context=None):
- assert mode in ['read', 'write', 'create', 'unlink'], \
+ assert mode in ['read', 'write', 'create', 'delete'], \
'Invalid access mode for security'
if user == 0:
return True
@@ -131,8 +131,8 @@ class ModelAccess(OSV):
self.check(cursor.dbname)
return res
- def unlink(self, cursor, user, ids, context=None):
- res = super(ModelAccess, self).unlink(cursor, user, ids,
+ def delete(self, cursor, user, ids, context=None):
+ res = super(ModelAccess, self).delete(cursor, user, ids,
context=context)
self.check(cursor.dbname)
return res
diff --git a/trytond/ir/model.xml b/trytond/ir/model.xml
index d698623a3b..a7bd2616d9 100644
--- a/trytond/ir/model.xml
+++ b/trytond/ir/model.xml
@@ -133,7 +133,7 @@
-
+
@@ -157,8 +157,8 @@
-
-
+
+
diff --git a/trytond/ir/module/module.py b/trytond/ir/module/module.py
index 9f335f2f98..eec2ab7b70 100644
--- a/trytond/ir/module/module.py
+++ b/trytond/ir/module/module.py
@@ -166,7 +166,7 @@ class Module(OSV):
'button_update_translations',
]
self._error_messages.update({
- 'unlink_state': 'You can not remove a module that is installed ' \
+ 'delete_state': 'You can not remove a module that is installed ' \
'or will be installed',
'missing_dep': 'Missing dependencies %s for module "%s"',
'uninstall_dep': 'The modules you are trying to uninstall ' \
@@ -204,7 +204,7 @@ class Module(OSV):
module.name).get('version', '')
return res
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
if not ids:
return True
if isinstance(ids, (int, long)):
@@ -216,8 +216,8 @@ class Module(OSV):
'to remove',
'to install',
):
- self.raise_user_error(cursor, 'unlink_state', context=context)
- return super(Module, self).unlink(cursor, user, ids, context=context)
+ self.raise_user_error(cursor, 'delete_state', context=context)
+ return super(Module, self).delete(cursor, user, ids, context=context)
def state_install(self, cursor, user, ids, context=None):
graph, packages, later = create_graph(get_module_list())
@@ -393,7 +393,7 @@ class Module(OSV):
dependency_ids = dependency_obj.search(cursor, user, [
('module', '=', module_id),
])
- dependency_obj.unlink(cursor, user, dependency_ids)
+ dependency_obj.delete(cursor, user, dependency_ids)
if depends is None:
depends = []
for depend in depends:
diff --git a/trytond/ir/property.py b/trytond/ir/property.py
index 4c16e036a5..f744276eb0 100644
--- a/trytond/ir/property.py
+++ b/trytond/ir/property.py
@@ -109,7 +109,7 @@ class Property(OSV):
('field', '=', field_id),
('res', '=', model + ',' + str(res_id)),
], context=context)
- self.unlink(cursor, user, property_ids, context=context)
+ self.delete(cursor, user, property_ids, context=context)
default_id = self.search(cursor, user, [
('field', '=', field_id),
diff --git a/trytond/ir/rule.py b/trytond/ir/rule.py
index 41667469a3..67fb888862 100644
--- a/trytond/ir/rule.py
+++ b/trytond/ir/rule.py
@@ -40,8 +40,8 @@ class RuleGroup(OSV):
def default_default_p(self, cursor, user, context=None):
return False
- def unlink(self, cursor, user, ids, context=None):
- res = super(RuleGroup, self).unlink(cursor, user, ids,
+ def delete(self, cursor, user, ids, context=None):
+ res = super(RuleGroup, self).delete(cursor, user, ids,
context=context)
# Restart the cache on the domain_get method of ir.rule
self.pool.get('ir.rule').domain_get(cursor.dbname)
@@ -227,8 +227,8 @@ class Rule(OSV):
domain_get = Cache('ir_rule.domain_get')(domain_get)
- def unlink(self, cursor, user, ids, context=None):
- res = super(Rule, self).unlink(cursor, user, ids, context=context)
+ def delete(self, cursor, user, ids, context=None):
+ res = super(Rule, self).delete(cursor, user, ids, context=context)
# Restart the cache on the domain_get method of ir.rule
self.domain_get(cursor.dbname)
return res
diff --git a/trytond/ir/translation.py b/trytond/ir/translation.py
index 9ec4035478..786fe8c00b 100644
--- a/trytond/ir/translation.py
+++ b/trytond/ir/translation.py
@@ -204,8 +204,6 @@ class Translation(OSV, Cacheable):
if source:
source = source.strip().replace('\n',' ')
- if isinstance(source, unicode):
- source = source.encode('utf8')
cursor.execute('SELECT value ' \
'FROM ir_translation ' \
'WHERE lang=%s ' \
@@ -271,10 +269,10 @@ class Translation(OSV, Cacheable):
res[(name, ttype, lang, source)])
return res
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
self.clear(cursor)
self.fields_view_get(cursor.dbname)
- return super(Translation, self).unlink(cursor, user, ids,
+ return super(Translation, self).delete(cursor, user, ids,
context=context)
def create(self, cursor, user, vals, context=None):
@@ -486,7 +484,7 @@ class ReportTranslationUpdate(Wizard):
return strings
if node.nodeValue:
- txt = node.nodeValue.encode('utf-8').strip()
+ txt = node.nodeValue.strip()
if txt:
strings.append(txt)
diff --git a/trytond/ir/ui/menu.py b/trytond/ir/ui/menu.py
index ce89dc9273..768f3f9074 100644
--- a/trytond/ir/ui/menu.py
+++ b/trytond/ir/ui/menu.py
@@ -162,7 +162,7 @@ class UIMenu(OSV):
('model', '=', self._name + ',' + str(menu_id)),
], context=context)
if action_keyword_ids:
- action_keyword_obj.unlink(cursor, user, action_keyword_ids,
+ action_keyword_obj.delete(cursor, user, action_keyword_ids,
context=ctx)
action_type, action_id = value.split(',')
action_obj = self.pool.get(action_type)
diff --git a/trytond/ir/ui/view.py b/trytond/ir/ui/view.py
index c8baec681f..a588aaa585 100644
--- a/trytond/ir/ui/view.py
+++ b/trytond/ir/ui/view.py
@@ -121,7 +121,7 @@ class View(OSV):
(view.model, 'view') + tuple(strings))
return True
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
@@ -132,7 +132,7 @@ class View(OSV):
self.pool.get(view.model).fields_view_get(cursor.dbname)
except:
pass
- res = super(View, self).unlink(cursor, user, ids, context=context)
+ res = super(View, self).delete(cursor, user, ids, context=context)
return res
def create(self, cursor, user, vals, context=None):
@@ -172,11 +172,11 @@ class View(OSV):
if element.get('string'):
string = element.get('string')
if string:
- strings.append(string.encode('utf-8'))
+ strings.append(string)
if element.get('sum'):
string = element.get('sum')
if string:
- strings.append(string.encode('utf-8'))
+ strings.append(string)
for child in element:
strings.extend(self._translate_view(child))
return strings
@@ -231,7 +231,7 @@ class ViewTreeWidth(OSV):
'set_width',
]
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
views = self.browse(cursor, user, ids, context=context)
@@ -241,7 +241,7 @@ class ViewTreeWidth(OSV):
self.pool.get(view.model).fields_view_get(cursor.dbname)
except:
pass
- res = super(ViewTreeWidth, self).unlink(cursor, user, ids, context=context)
+ res = super(ViewTreeWidth, self).delete(cursor, user, ids, context=context)
return res
def create(self, cursor, user, vals, context=None):
@@ -285,7 +285,7 @@ class ViewTreeWidth(OSV):
('model', '=', model),
('field', 'in', fields.keys()),
], context=context)
- self.unlink(cursor, user, ids, context=context)
+ self.delete(cursor, user, ids, context=context)
for field in fields.keys():
self.create(cursor, user, {
diff --git a/trytond/module.py b/trytond/module.py
index 5b6e7ad27a..de3209694c 100644
--- a/trytond/module.py
+++ b/trytond/module.py
@@ -7,6 +7,7 @@ import tools
import pooler
from netsvc import Logger, LOG_ERROR, LOG_INFO
import zipfile
+import zipimport
OPJ = os.path.join
MODULES_PATH = OPJ(os.path.dirname(__file__), 'modules')
@@ -277,17 +278,22 @@ def register_classes():
continue
if not os.path.isfile(OPJ(MODULES_PATH, module+'.zip')):
- # XXX must restrict to only modules paths
- imp.load_module(module, *imp.find_module(module))
+ try:
+ imp.load_module(module, *imp.find_module(module,
+ [MODULES_PATH]))
+ except ImportError:
+ Logger().notify_channel('init', LOG_ERROR,
+ 'Couldn\'t import module %s' % module)
+ break
else:
- import zipimport
mod_path = OPJ(MODULES_PATH, module+'.zip')
try:
zimp = zipimport.zipimporter(mod_path)
zimp.load_module(module)
except zipimport.ZipImportError:
Logger().notify_channel('init', LOG_ERROR,
- 'Couldn\'t find module %s' % module)
+ 'Couldn\'t import module %s' % module)
+ break
def load_modules(database, update_module=False, lang=None):
cursor = database.cursor()
@@ -328,7 +334,7 @@ def load_modules(database, update_module=False, lang=None):
'WHERE module = %s ' \
'ORDER BY id DESC', (mod_name,))
for rmod, rid in cursor.fetchall():
- pool.get(rmod).unlink(cursor, 0, [rid])
+ pool.get(rmod).delete(cursor, 0, rid)
cursor.commit()
cursor.execute("UPDATE ir_module_module SET state = %s " \
"WHERE state IN ('to remove')", ('uninstalled',))
diff --git a/trytond/netsvc.py b/trytond/netsvc.py
index 93daef440e..7690b74ded 100644
--- a/trytond/netsvc.py
+++ b/trytond/netsvc.py
@@ -360,14 +360,15 @@ class TinySocketClientThread(threading.Thread):
class TinySocketServerThread(threading.Thread):
def __init__(self, interface, port, secure=False):
threading.Thread.__init__(self)
- familly = socket.AF_INET
+ self.socket = None
if socket.has_ipv6:
try:
socket.getaddrinfo(interface or None, port, socket.AF_INET6)
- familly = socket.AF_INET6
+ self.socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
except:
pass
- self.socket = socket.socket(familly, socket.SOCK_STREAM)
+ if self.socket is None:
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if secure:
self.socket = start_SSL(self.socket)
diff --git a/trytond/osv/fields.py b/trytond/osv/fields.py
index 6e0602cd48..3831f75e5b 100644
--- a/trytond/osv/fields.py
+++ b/trytond/osv/fields.py
@@ -14,13 +14,13 @@
Relationals fields
- Values: ('create', { fields }) create
- ('write', ID, { fields }) modification
- ('unlink', ID) remove (delete)
- ('remove', ID) unlink one (target id or target of relation)
- ('add', ID) link
- ('remove_all') unlink all
- ('set', ids) set a list of links
+ Values: ('create', { fields }) create
+ ('write', ids, { fields }) modification
+ ('delete', ids) remove (delete)
+ ('unlink', ids) unlink one (target id or target of relation)
+ ('add', ids) link
+ ('unlink_all') unlink all
+ ('set', ids) set a list of links
"""
import psycopg2
@@ -31,9 +31,11 @@ import sha
def _symbol_f(symb):
if symb is None or symb == False:
return None
+ elif isinstance(symb, str):
+ return unicode(symb, 'utf-8')
elif isinstance(symb, unicode):
- return symb.encode('utf-8')
- return str(symb)
+ return symb
+ return unicode(symb)
class Column(object):
_classic_read = True
@@ -49,7 +51,8 @@ class Column(object):
def __init__(self, string='unknown', required=False, readonly=False,
domain=None, context='', states=None, priority=0,
change_default=False, size=None, ondelete="set null",
- translate=False, select=0, on_change=None, **args):
+ translate=False, select=0, on_change=None, on_change_with=None,
+ **args):
self.states = states or {}
self.string = string
self.readonly = readonly
@@ -68,6 +71,7 @@ class Column(object):
raise Exception('Error', 'Select must be one of 0, 1, 2')
self.select = select
self.on_change = on_change
+ self.on_change_with = on_change_with
self.order_field = None
for i in args:
if args[i]:
@@ -163,28 +167,6 @@ class Char(Column):
def __init__(self, string, size=None, **args):
Column.__init__(self, string=string, size=size, **args)
- self._symbol_set = (self._symbol_c, self._symbol_set_char)
-
- def _symbol_set_char(self, symb):
- """
- takes a string (encoded in utf8)
- and returns a string (encoded in utf8)
- """
- #TODO we need to remove the "symb==False" from the next line BUT
- #TODO for now too many things rely on this broken behavior
- #TODO the 'symb is None' test should be common to all data types
- if symb is None or symb == False:
- return None
-
- # we need to convert the string to a unicode object to be able
- # to evaluate its length (and possibly truncate it) reliably
- if isinstance(symb, str):
- u_symb = unicode(symb, 'utf8')
- elif isinstance(symb, unicode):
- u_symb = symb
- else:
- u_symb = unicode(symb)
- return u_symb.encode('utf8')
def sql_type(self):
if self.size:
@@ -235,12 +217,6 @@ float = Float
class Numeric(Float):
_type = 'numeric'
- def __init__(self, string='unknown', digits=None, **args):
- Float.__init__(self, string=string, digits=digits, **args)
- if self.digits:
- self._symbol_f = lambda x: round(x, self.digits[1])
- self._symbol_set = (self._symbol_c, self._symbol_f)
-
def sql_type(self):
return ('numeric', 'numeric')
@@ -351,21 +327,22 @@ class Many2One(Column):
table = obj_src.pool.get(self._obj)._table
if type(values) == type([]):
for act in values:
- if act[0] == 0:
- id_new = obj.create(cursor, act[2])
+ if act[0] == 'create':
+ id_new = obj.create(cursor, user, act[2], context=context)
cursor.execute('UPDATE "' + obj_src._table + '" ' \
'SET "' + field + '" = %s ' \
'WHERE id = %s', (id_new, obj_id))
- elif act[0] == 1:
- obj.write(cursor, [act[1]], act[2], context=context)
- elif act[0] == 2:
+ elif act[0] == 'write':
+ obj.write(cursor, act[1], act[2], context=context)
+ elif act[0] == 'delete':
+ obj.delete(cursor, user, act[1], context=context)
cursor.execute('DELETE FROM "' + table + '" ' \
'WHERE id = %s', (act[1],))
- elif act[0] == 3 or act[0] == 5:
+ elif act[0] == 'unlink' or act[0] == 'unlink_all':
cursor.execute('UPDATE "' + obj_src._table + '" ' \
'SET "' + field + '" = NULL ' \
'WHERE id = %s', (obj_id,))
- elif act[0] == 4:
+ elif act[0] == 'add':
cursor.execute('UPDATE "' + obj_src._table + '" ' \
'SET "' + field + '" = %s ' \
'WHERE id = %s', (act[1], obj_id))
@@ -434,39 +411,53 @@ class One2Many(Column):
obj.create(cursor, user, act[1], context=context)
elif act[0] == 'write':
act[2][self._field] = obj_id
- obj.write(cursor, user, [act[1]] , act[2], context=context)
+ obj.write(cursor, user, act[1] , act[2], context=context)
+ elif act[0] == 'delete':
+ obj.delete(cursor, user, act[1], context=context)
elif act[0] == 'unlink':
- obj.unlink(cursor, user, [act[1]], context=context)
- elif act[0] == 'remove':
+ if isinstance(act[1], (int, long)):
+ ids = [act[1]]
+ else:
+ ids = list(act[1])
+ if not ids:
+ continue
cursor.execute('UPDATE "' + _table + '" ' \
'SET "' + self._field + '" = NULL ' \
- 'WHERE id = %s '\
- 'AND "' + self._field + '" = %s', (act[1], obj_id))
+ 'WHERE id IN (' \
+ + ','.join(['%s' for x in ids]) + ') ' \
+ 'AND "' + self._field + '" = %s',
+ ids + [obj_id])
elif act[0] == 'add':
+ if isinstance(act[1], (int, long)):
+ ids = [act[1]]
+ else:
+ ids = list(act[1])
cursor.execute('UPDATE "' + _table + '" ' \
'SET "' + self._field + '" = %s ' \
- 'WHERE id = %s', (obj_id, act[1]))
- elif act[0] == 'remove_all':
+ 'WHERE id IN (' \
+ + ','.join(['%s' for x in ids]) + ')',
+ [obj_id] + ids)
+ elif act[0] == 'unlink_all':
cursor.execute('UPDATE "' + _table + '" ' \
'SET "' + self._field + '" = NULL ' \
'WHERE "' + self._field + '" = %s', (obj_id,))
elif act[0] == 'set':
if not act[1]:
- ids2 = [0]
+ ids = [0]
else:
- ids2 = act[1]
+ ids = list(act[1])
cursor.execute('UPDATE "' + _table + '" ' \
'SET "' + self._field + '" = NULL ' \
'WHERE "' + self._field + '" = %s ' \
'AND id not IN (' + \
- ','.join([str(x) for x in ids2]) + ')',
- (obj_id,))
+ ','.join(['%s' for x in ids]) + ')',
+ [obj_id] + ids)
if act[1]:
cursor.execute('UPDATE "' + _table + '" ' \
'SET "' + self._field + '" = %s ' \
'WHERE id IN (' + \
- ','.join([str(x) for x in act[1]]) + ')',
- (obj_id,))
+ ','.join(['%s' for x in ids]) + ')',
+ [obj_id] + ids)
else:
raise Exception('Bad arguments')
@@ -528,33 +519,54 @@ class Many2Many(Column):
obj = obj.pool.get(self._obj)
for act in values:
if act[0] == 'create':
- idnew = obj.create(cursor, user, act[1])
+ idnew = obj.create(cursor, user, act[1], context=context)
cursor.execute('INSERT INTO "' + self._rel + '" ' \
'(' + self._id1 + ', ' + self._id2 + ') ' \
'VALUES (%s, %s)', (obj_id, idnew))
elif act[0] == 'write':
- obj.write(cursor, user, [act[1]] , act[2], context=context)
+ obj.write(cursor, user, act[1] , act[2], context=context)
+ elif act[0] == 'delete':
+ obj.delete(cursor, user, act[1], context=context)
elif act[0] == 'unlink':
- obj.unlink(cursor, user, [act[1]], context=context)
- elif act[0] == 'remove':
+ if isinstance(act[1], (int, long)):
+ ids = [act[1]]
+ else:
+ ids = list(act[1])
+ if not ids:
+ continue
cursor.execute('DELETE FROM "' + self._rel + '" ' \
'WHERE "' + self._id1 + '" = %s ' \
- 'AND "'+ self._id2 + '" = %s', (obj_id, act[1]))
+ 'AND "'+ self._id2 + '" IN (' \
+ + ','.join(['%s' for x in ids]) + ')',
+ [obj_id] + ids)
elif act[0] == 'add':
- cursor.execute('SELECT * FROM "' + self._rel + '" ' \
+ if isinstance(act[1], (int, long)):
+ ids = [act[1]]
+ else:
+ ids = list(act[1])
+ cursor.execute('SELECT "' + self._id2 + '" ' \
+ 'FROM "' + self._rel + '" ' \
'WHERE ' + self._id1 + ' = %s ' \
- 'AND ' + self._id2 + ' = %s ',
- (obj_id, act[1]))
- if cursor.rowcount:
- continue
- cursor.execute('INSERT INTO "' + self._rel + '" ' \
- '(' + self._id1 + ', ' + self._id2 + ') ' \
- 'VALUES (%s, %s)', (obj_id, act[1]))
- elif act[0] == 'remove_all':
+ 'AND ' + self._id2 + ' IN (' + \
+ ','.join(['%s' for x in ids]) + ')',
+ [obj_id] + ids)
+ existing_ids = []
+ for row in cursor.fetchall():
+ existing_ids.append(row[0])
+ new_ids = [x for x in ids if x not in existing_ids]
+ for new_id in new_ids:
+ cursor.execute('INSERT INTO "' + self._rel + '" ' \
+ '("' + self._id1 + '", "' + self._id2 + '") ' \
+ 'VALUES (%s, %s)', (obj_id, new_id))
+ elif act[0] == 'unlink_all':
cursor.execute('UPDATE "' + self._rel + '" ' \
'SET "' + self._id2 + '" = NULL ' \
'WHERE "' + self._id2 + '" = %s', (obj_id,))
elif act[0] == 'set':
+ if not act[1]:
+ ids = []
+ else:
+ ids = list(act[1])
domain1, domain2 = obj.pool.get('ir.rule').domain_get(cursor,
user, obj._name)
if domain1:
@@ -569,10 +581,10 @@ class Many2Many(Column):
obj._table + '.id ' + domain1 + ')',
[obj_id, obj_id] + domain2)
- for act_nbr in act[1]:
+ for new_id in ids:
cursor.execute('INSERT INTO "' + self._rel + '" ' \
- '(' + self._id1 + ', ' + self._id2 + ') ' \
- 'VALUES (%s, %s)', (obj_id, act_nbr))
+ '("' + self._id1 + '", "' + self._id2 + '") ' \
+ 'VALUES (%s, %s)', (obj_id, new_id))
else:
raise Exception('Bad arguments')
diff --git a/trytond/osv/orm.py b/trytond/osv/orm.py
index 50eaa78fb8..02ee76879c 100644
--- a/trytond/osv/orm.py
+++ b/trytond/osv/orm.py
@@ -10,6 +10,7 @@ import datetime
from lxml import etree
import copy
from trytond.sql_db import table_handler
+from decimal import Decimal
ID_MAX = 1000
@@ -499,7 +500,7 @@ class ORM(object):
'write',
'create',
'default_get',
- 'unlink',
+ 'delete',
'fields_get',
'fields_view_get',
'search',
@@ -554,6 +555,10 @@ class ORM(object):
on_change = 'on_change_' + name
if on_change not in self._rpc_allowed:
self._rpc_allowed.append(on_change)
+ if self._columns[name].on_change_with:
+ on_change_with = 'on_change_with_' + name
+ if on_change_with not in self._rpc_allowed:
+ self._rpc_allowed.append(on_change_with)
for k in self._defaults:
assert (k in self._columns) or (k in self._inherit_fields), \
@@ -1141,7 +1146,7 @@ class ORM(object):
res.update(val)
return res
- def unlink(self, cursor, user, ids, context=None):
+ def delete(self, cursor, user, ids, context=None):
'''
Remove the ids.
'''
@@ -1170,7 +1175,7 @@ class ORM(object):
del context['read_delta']
self.pool.get('ir.model.access').check(cursor, user, self._name,
- 'unlink')
+ 'delete')
cursor.execute(
"SELECT id FROM wkf_instance "\
@@ -1190,13 +1195,6 @@ class ORM(object):
error_description='xml_record_desc',
context=context)
- #cursor.execute('select * from ' + self._table + \
- # ' where id in ('+str_d+')', ids)
- #res = cursor.dictfetchall()
- #for key in self._inherits:
- # ids2 = [x[self._inherits[key]] for x in res]
- # self.pool.get(key).unlink(cursor, user, ids2)
-
domain1, domain2 = self.pool.get('ir.rule').domain_get(cursor, user,
self._name)
if domain1:
@@ -1237,23 +1235,25 @@ class ORM(object):
# Allow root user to update/delete
if user == 0:
return True
- cursor.execute('SELECT values '\
- 'FROM ir_model_data '\
- 'WHERE model = %s '\
- 'AND db_id in (' + ','.join('%s' for x in ids)+ ') ',
- [self._name]+ids)
+ cursor.execute('SELECT values ' \
+ 'FROM ir_model_data ' \
+ 'WHERE model = %s ' \
+ 'AND db_id in (' + ','.join('%s' for x in ids)+ ') ',
+ [self._name] + ids)
if cursor.rowcount == 0:
return True
if values == None:
return False
for line in cursor.fetchall():
- xml_values = eval(line[0])
+ xml_values = eval(line[0], {
+ 'Decimal': Decimal,
+ 'datetime': datetime,
+ })
for key, val in values.iteritems():
if key in xml_values and val != xml_values[key]:
return False
return True
- # TODO: Validate
def write(self, cursor, user, ids, vals, context=None):
'''
Update ids with the content of vals.
@@ -1636,6 +1636,7 @@ class ORM(object):
'select',
'on_change',
'add_remove',
+ 'on_change_with',
):
if getattr(self._columns[field], arg, False):
res[field][arg] = getattr(self._columns[field], arg)
@@ -1903,7 +1904,7 @@ class ORM(object):
if not sql_res:
break
test = sql_res[4]
- view_id = test or sql_res[3]
+ view_id = test or sql_res[2]
model = False
# if a view was found
@@ -1924,7 +1925,8 @@ class ORM(object):
return result
result['arch'] = _inherit_apply_rec(result['arch'], sql_res[2])
- result['field_childs'] = sql_res[2] or False
+
+ result['field_childs'] = sql_res[1] or False
# otherwise, build some kind of default view
else:
if view_type == 'form':
@@ -2320,14 +2322,8 @@ class ORM(object):
else:
add_null = False
if arg[1] in ('like', 'ilike'):
- if isinstance(arg[2], str):
- str_utf8 = arg[2]
- elif isinstance(arg[2], unicode):
- str_utf8 = arg[2].encode('utf-8')
- else:
- str_utf8 = str(arg[2])
- qu2.append('%%%s%%' % str_utf8)
- if not str_utf8:
+ qu2.append('%%%s%%' % arg[2])
+ if not arg[2]:
add_null = True
else:
if arg[0] in table._columns:
diff --git a/trytond/osv/osv.py b/trytond/osv/osv.py
index d717ab5f41..f93c667afb 100644
--- a/trytond/osv/osv.py
+++ b/trytond/osv/osv.py
@@ -6,7 +6,7 @@ from trytond.netsvc import Service, LocalService, Logger, LOG_ERROR
from trytond import pooler
import copy
import sys
-from psycopg2 import IntegrityError
+from trytond.sql_db import IntegrityError
from trytond.tools import UpdateableDict
import traceback
from trytond.tools import Cache
@@ -50,11 +50,17 @@ class OSVService(Service):
'ConcurrencyException') \
and not CONFIG['verbose']:
raise
+ if isinstance(exception, IntegrityError) and not CONFIG['verbose']:
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
tb_s = reduce(lambda x, y: x+y,
traceback.format_exception(*sys.exc_info()))
logger = Logger()
logger.notify_channel("web-services", LOG_ERROR,
'Exception in call: \n' + tb_s)
+ if isinstance(exception, IntegrityError):
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
raise
def execute(self, dbname, user, object_name, method, *args, **kargs):
@@ -83,11 +89,17 @@ class OSVService(Service):
'ConcurrencyException') \
and not CONFIG['verbose']:
raise
+ if isinstance(exception, IntegrityError) and not CONFIG['verbose']:
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
tb_s = reduce(lambda x, y: x+y,
traceback.format_exception(*sys.exc_info()))
logger = Logger()
logger.notify_channel("web-services", LOG_ERROR,
'Exception in call: \n' + tb_s)
+ if isinstance(exception, IntegrityError):
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
raise
return True
diff --git a/trytond/pysocket.py b/trytond/pysocket.py
index e2e0b2e1a7..cddcee9ef8 100644
--- a/trytond/pysocket.py
+++ b/trytond/pysocket.py
@@ -36,26 +36,29 @@ class PySocket:
if host in DNS_CACHE:
host = DNS_CACHE[host]
if not self.sock:
- familly = socket.AF_INET
+ self.sock = None
if socket.has_ipv6:
try:
socket.getaddrinfo(host, int(port), socket.AF_INET6)
- familly = socket.AF_INET6
+ self.sock = socket.socket(socket.AF_INET6,
+ socket.SOCK_STREAM)
except:
pass
- self.sock = socket.socket(familly, socket.SOCK_STREAM)
+ if self.sock is None:
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(120)
self.sock.connect((host, int(port)))
DNS_CACHE[hostname], port = self.sock.getpeername()[:2]
try:
- familly = socket.AF_INET
+ sock = None
if socket.has_ipv6:
try:
socket.getaddrinfo(host, int(port), socket.AF_INET6)
- familly = socket.AF_INET6
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
except:
pass
- sock = socket.socket(familly, socket.SOCK_STREAM)
+ if sock is None:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(120)
sock.connect((host, int(port)))
ssl_sock = socket.ssl(sock)
@@ -94,16 +97,17 @@ class PySocket:
def reconnect(self):
if self.host and self.port:
self.disconnect()
- familly = socket.AF_INET
+ self.sock = None
if socket.has_ipv6:
try:
socket.getaddrinfo(self.host, int(self.port),
socket.AF_INET6)
- familly = socket.AF_INET6
+ self.sock = socket.socket(socket.AF_INET6,
+ socket.SOCK_STREAM)
except:
pass
- self.sock = socket.socket(
- familly, socket.SOCK_STREAM)
+ if self.sock is None:
+ self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.sock.settimeout(120)
self.sock.connect((self.host, int(self.port)))
if self.ssl:
diff --git a/trytond/report/report.py b/trytond/report/report.py
index 01f622c692..07f82a5367 100644
--- a/trytond/report/report.py
+++ b/trytond/report/report.py
@@ -1,6 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms.
"Report"
-from trytond.netsvc import Service, service_exist, Logger, LOG_ERROR
+from trytond.netsvc import Service, service_exist, Logger, LOG_WARNING, LOG_ERROR
from trytond import pooler
import copy
import xml
@@ -25,6 +25,7 @@ import tempfile
from genshi.filters import Translator
import traceback
from trytond.config import CONFIG
+from trytond.sql_db import IntegrityError
MODULE_LIST = []
MODULE_CLASS_LIST = {}
@@ -193,10 +194,16 @@ class ReportService(Service):
'ConcurrencyException') \
and not CONFIG['verbose']:
raise
+ if isinstance(exception, IntegrityError) and not CONFIG['verbose']:
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
tb_s = reduce(lambda x, y: x+y,
traceback.format_exception(*sys.exc_info()))
Logger().notify_channel("web-services", LOG_ERROR,
'Exception in call: ' + tb_s)
+ if isinstance(exception, IntegrityError):
+ raise Exception('UserError', 'Constraint Error',
+ *exception.args)
raise
def execute(self, dbname, user, report_name, ids, datas, context=None):
@@ -342,6 +349,7 @@ class Report(object):
browse(cursor, user, user)
localcontext['formatLang'] = self.format_lang
localcontext['decodestring'] = decodestring
+ localcontext['StringIO'] = StringIO.StringIO
localcontext['time'] = time
localcontext['datetime'] = datetime
localcontext.update(context)
@@ -477,12 +485,14 @@ class Report(object):
encoding = 'UTF-8'
if encoding == 'cp1252':
encoding = '1252'
+ if not encoding:
+ encoding = 'UTF-8'
try:
if os.name == 'nt':
language = _LOCALE2WIN32.get(language, language)
locale.setlocale(locale.LC_ALL, str(language + '.' + encoding))
except Exception:
- Logger().notify_channel('web-service', LOG_ERROR,
+ Logger().notify_channel('web-service', LOG_WARNING,
'Report %s: unable to set locale "%s"' % \
(self._name, language + '.' + encoding))
if date:
diff --git a/trytond/res/group.xml b/trytond/res/group.xml
index 380858786e..a768490865 100644
--- a/trytond/res/group.xml
+++ b/trytond/res/group.xml
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/trytond/res/ir.xml b/trytond/res/ir.xml
index b096361e42..5cef534191 100644
--- a/trytond/res/ir.xml
+++ b/trytond/res/ir.xml
@@ -7,7 +7,7 @@
-
+
@@ -15,14 +15,14 @@
-
+
-
+
@@ -30,14 +30,14 @@
-
+
-
+
@@ -60,14 +60,14 @@
-
+
-
+
@@ -75,14 +75,14 @@
-
+
-
+
@@ -90,14 +90,14 @@
-
+
-
+
@@ -105,14 +105,14 @@
-
+
-
+
@@ -120,14 +120,14 @@
-
+
-
+
@@ -135,14 +135,14 @@
-
+
-
+
@@ -150,14 +150,14 @@
-
+
-
+
@@ -165,14 +165,14 @@
-
+
-
+
@@ -180,14 +180,14 @@
-
+
-
+
@@ -195,14 +195,14 @@
-
+
-
+
@@ -210,14 +210,14 @@
-
+
-
+
@@ -225,14 +225,14 @@
-
+
-
+
@@ -240,14 +240,14 @@
-
+
-
+
@@ -255,14 +255,14 @@
-
+
-
+
@@ -270,14 +270,14 @@
-
+
-
+
@@ -285,14 +285,14 @@
-
+
-
+
@@ -300,14 +300,14 @@
-
+
-
+
@@ -315,14 +315,14 @@
-
+
-
+
@@ -330,14 +330,14 @@
-
+
-
+
@@ -345,14 +345,14 @@
-
+
-
+
@@ -360,7 +360,7 @@
-
+