[BACKPORT] Stable fixes and refactorings to Trunk

bzr revid: jvo@tinyerp.com-20100520063044-sviy1e9pybirhpsw
This commit is contained in:
Jay (Open ERP) 2010-05-20 12:00:44 +05:30
commit e3ccef27d3
33 changed files with 1331 additions and 384 deletions

View File

@ -9,7 +9,8 @@ include bin/server.pkey
include bin/gpl.txt
include man/openerp-server.1
include man/openerp_serverrc.5
recursive-include pixmaps
recursive-include pixmaps *
recursive-include win32 *
recursive-include doc *
recursive-include bin *xml *xsl *sql *rml *sxw *csv *rng
graft bin/addons/

View File

@ -1302,14 +1302,14 @@
<field name="subject" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<field name="message" select="2" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e.[[ object.partner_id.name ]]" align="0.0"/>
<label colspan="4" string="Access all the fields related to the current object using expressions, i.e. object.partner_id.name " align="0.0"/>
</page>
<page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}">
<separator colspan="4" string="SMS Configuration"/>
<field name="mobile" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','sms')]}"/>
<field name="sms" colspan="4" attrs="{'required':[('state','=','sms')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
<label colspan="4" string="Access all the fields related to the current object using expressions, i.e. object.partner_id.name " align="0.0"/>
</page>
<page string="Create / Write / Copy" attrs="{'invisible':[('state','!=','object_create'), ('state','!=','object_write'), ('state','!=','object_copy')]}">
<separator colspan="4" string="Fields Mapping"/>

View File

@ -455,7 +455,7 @@ class actions_server(osv.osv):
'type': lambda *a: 'ir.actions.server',
'sequence': lambda *a: 5,
'code': lambda *a: """# You can use the following variables
# - object
# - object or obj
# - time
# - cr
# - uid
@ -532,7 +532,6 @@ class actions_server(osv.osv):
def run(self, cr, uid, ids, context={}):
logger = netsvc.Logger()
for action in self.browse(cr, uid, ids, context):
obj_pool = self.pool.get(action.model_id.model)
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
@ -554,19 +553,26 @@ class actions_server(osv.osv):
return self.pool.get(action.action_id.type)\
.read(cr, uid, action.action_id.id, context=context)
if action.state == 'code':
localdict = {
'self': self.pool.get(action.model_id.model),
'context': context,
'time': time,
'ids': ids,
'cr': cr,
'uid': uid,
'object':obj
}
exec action.code in localdict
if 'action' in localdict:
return localdict['action']
if config['server_actions_allow_code']:
localdict = {
'self': self.pool.get(action.model_id.model),
'context': context,
'time': time,
'ids': ids,
'cr': cr,
'uid': uid,
'object':obj,
'obj': obj,
}
exec action.code in localdict
if 'action' in localdict:
return localdict['action']
else:
netsvc.Logger().notifyChannel(
self._name, netsvc.LOG_ERROR,
"%s is a `code` server action, but "
"it isn't allowed in this configuration.\n\n"
"See server options to enable it"%action)
if action.state == 'email':
user = config['email_from']
@ -580,7 +586,7 @@ class actions_server(osv.osv):
logger.notifyChannel('email', netsvc.LOG_INFO, 'Partner Email address not Specified!')
continue
if not user:
raise osv.except_osv(_('Error'), _("Please specify server option --smtp-from !"))
raise osv.except_osv(_('Error'), _("Please specify server option --email-from !"))
subject = self.merge_message(cr, uid, action.subject, action, context)
body = self.merge_message(cr, uid, action.message, action, context)

View File

@ -146,16 +146,19 @@ class ir_cron(osv.osv, netsvc.Agent):
def create(self, cr, uid, vals, context=None):
res = super(ir_cron, self).create(cr, uid, vals, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
def write(self, cr, user, ids, vals, context=None):
res = super(ir_cron, self).write(cr, user, ids, vals, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
def unlink(self, cr, uid, ids, context=None):
res = super(ir_cron, self).unlink(cr, uid, ids, context=context)
cr.commit()
self.cancel(cr.dbname)
self._poolJobs(cr.dbname)
return res
ir_cron()

View File

@ -82,6 +82,8 @@ class ir_model(osv.osv):
return super(ir_model,self).write(cr, user, ids, vals, context)
def create(self, cr, user, vals, context=None):
if context is None:
context = {}
if context and context.get('manual',False):
vals['state']='manual'
res = super(ir_model,self).create(cr, user, vals, context)
@ -260,6 +262,8 @@ class ir_model_fields(osv.osv):
if 'model_id' in vals:
model_data = self.pool.get('ir.model').browse(cr, user, vals['model_id'])
vals['model'] = model_data.model
if context is None:
context = {}
if context and context.get('manual',False):
vals['state'] = 'manual'
res = super(ir_model_fields,self).create(cr, user, vals, context)
@ -267,7 +271,7 @@ class ir_model_fields(osv.osv):
if not vals['name'].startswith('x_'):
raise except_orm(_('Error'), _("Custom fields must have a name that starts with 'x_' !"))
if 'relation' in vals and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]):
if vals.get('relation',False) and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['relation'])]):
raise except_orm(_('Error'), _("Model %s Does not Exist !" % vals['relation']))
if self.pool.get(vals['model']):
@ -286,7 +290,7 @@ class ir_model_access(osv.osv):
_columns = {
'name': fields.char('Name', size=64, required=True),
'model_id': fields.many2one('ir.model', 'Object', required=True),
'group_id': fields.many2one('res.groups', 'Group'),
'group_id': fields.many2one('res.groups', 'Group', ondelete='cascade'),
'perm_read': fields.boolean('Read Access'),
'perm_write': fields.boolean('Write Access'),
'perm_create': fields.boolean('Create Access'),
@ -453,7 +457,7 @@ class ir_model_data(osv.osv):
def _get_id(self, cr, uid, module, xml_id):
ids = self.search(cr, uid, [('module','=',module),('name','=', xml_id)])
if not ids:
raise Exception('No references to %s.%s' % (module, xml_id))
raise ValueError('No references to %s.%s' % (module, xml_id))
# the sql constraints ensure us we have only one result
return ids[0]

View File

@ -150,8 +150,8 @@ class ir_translation(osv.osv):
if not context:
context = {}
ids = super(ir_translation, self).create(cursor, user, vals, context=context)
for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, [ids], ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
return ids
@ -159,16 +159,16 @@ class ir_translation(osv.osv):
if not context:
context = {}
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
return result
def unlink(self, cursor, user, ids, context=None):
if not context:
context = {}
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], lang=context.get('lang','en_US'))
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], source=trans_obj['src'])
self._get_ids.clear_cache(cursor.dbname, user, trans_obj['name'], trans_obj['type'], context.get('lang','en_US'), [trans_obj['res_id']])
result = super(ir_translation, self).unlink(cursor, user, ids, context=context)
return result

View File

@ -31,6 +31,10 @@ def one_in(setA, setB):
return True
return False
def cond(C, X, Y):
if C: return X
return Y
class many2many_unique(fields.many2many):
def set(self, cr, obj, id, name, values, user=None, context=None):
if not values:
@ -63,19 +67,24 @@ class ir_ui_menu(osv.osv):
# radical but this doesn't frequently happen
self._cache = {}
def search(self, cr, uid, args, offset=0, limit=2000, order=None,
context=None, count=False):
if context is None:
context = {}
ids = osv.orm.orm.search(self, cr, uid, args, offset, limit, order, context=context, count=(count and uid==1))
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
super_offset = cond(uid == 1, offset, 0)
super_limit = cond(uid == 1, limit, None)
super_count = cond(uid == 1, count, False)
ids = super(ir_ui_menu, self).search(cr, uid, args, super_offset,
super_limit, order,
context=context, count=super_count)
if uid == 1 or count:
return ids
if not ids:
if count:
return 0
return []
if count and ids:
return ids
modelaccess = self.pool.get('ir.model.access')
user_groups = set(self.pool.get('res.users').read(cr, 1, uid, ['groups_id'])['groups_id'])
@ -123,6 +132,11 @@ class ir_ui_menu(osv.osv):
result.append(menu.id)
self._cache[key] = True
if offset:
result = result[long(offset):]
if limit:
result = result[:long(limit)]
if count:
return len(result)
return result

View File

@ -200,6 +200,10 @@ class view_sc(osv.osv):
'resource': lambda *a: 'ir.ui.menu',
'user_id': lambda obj, cr, uid, context: uid,
}
_sql_constraints = [
('shortcut_unique', 'unique(res_id, user_id)', 'Shortcut for this menu already exists!'),
]
view_sc()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -146,11 +146,13 @@ class module(osv.osv):
], string='State', readonly=True),
'demo': fields.boolean('Demo data'),
'license': fields.selection([
('GPL-2', 'GPL-2'),
('GPL-2', 'GPL Version 2'),
('GPL-2 or any later version', 'GPL-2 or later version'),
('GPL-3', 'GPL-3'),
('GPL-3', 'GPL Version 3'),
('GPL-3 or any later version', 'GPL-3 or later version'),
('Other proprietary', 'Other proprietary')
('AGPL-3', 'Affero GPL-3'),
('Other OSI approved licence', 'Other OSI Approved Licence'),
('Other proprietary', 'Other Proprietary')
], string='License', readonly=True),
'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta", store=True),
'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta", store=True),
@ -161,7 +163,7 @@ class module(osv.osv):
_defaults = {
'state': lambda *a: 'uninstalled',
'demo': lambda *a: False,
'license': lambda *a: 'GPL-2',
'license': lambda *a: 'AGPL-3',
}
_order = 'name'

View File

@ -275,6 +275,26 @@
<field name="type">default</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_8delivery" model="res.partner.address">
<field name="city">Wavre</field>
<field name="name">Paul Lelitre</field>
<field name="zip">5478</field>
<field name="title">M.</field>
<field model="res.country" name="country_id" search="[('name','=','Belgium')]"/>
<field name="street">71 rue de Chimay</field>
<field name="type">delivery</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_8invoice" model="res.partner.address">
<field name="city">Wavre</field>
<field name="name">Serge Lelitre</field>
<field name="zip">5478</field>
<field name="title">M.</field>
<field model="res.country" name="country_id" search="[('name','=','Belgium')]"/>
<field name="street">69 rue de Chimay</field>
<field name="type">invoice</field>
<field name="partner_id" ref="res_partner_agrolait"/>
</record>
<record id="res_partner_address_9" model="res.partner.address">
<field name="city">Paris</field>
<field name="name">Arthur Grosbonnet</field>

View File

@ -60,11 +60,11 @@ class lang(osv.osv):
('name_uniq', 'unique (name)', 'The name of the language must be unique !'),
('code_uniq', 'unique (code)', 'The code of the language must be unique !'),
]
@tools.cache(skiparg=3)
def _lang_data_get(self, cr, uid, lang_id, monetary=False):
conv = localeconv()
lang_obj=self.browse(cr,uid,lang_id)
lang_obj = self.browse(cr, uid, lang_id)
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
@ -80,6 +80,7 @@ class lang(osv.osv):
if not grouping:
return (s, 0)
result = ""
seps = 0
spaces = ""
@ -129,7 +130,7 @@ class lang(osv.osv):
parts = formatted.split('.')
if grouping:
parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary, grouping=lang_grouping, thousands_sep=thousands_sep)
parts[0], seps = self._group(cr,uid,ids,parts[0], monetary=monetary, grouping=lang_grouping, thousands_sep=thousands_sep)
formatted = decimal_point.join(parts)
while seps:

View File

@ -6,9 +6,13 @@
<field name="name">Partner Manager</field>
</record>
<record model="ir.ui.menu" id="menu_base_config">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="menu_base_partner">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="menu_base_config">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
</data>
</openerp>

View File

@ -106,10 +106,11 @@ roles()
def _lang_get(self, cr, uid, context={}):
obj = self.pool.get('res.lang')
ids = obj.search(cr, uid, [])
ids = obj.search(cr, uid, [('translatable','=',True)])
res = obj.read(cr, uid, ids, ['code', 'name'], context)
res = [(r['code'], r['name']) for r in res]
return res
def _tz_get(self,cr,uid, context={}):
return [(x, x) for x in pytz.all_timezones]
@ -245,6 +246,15 @@ class users(osv.osv):
result = override_password(result)
else:
result = map(override_password, result)
if isinstance(result, list):
for rec in result:
if not rec.get('action_id',True):
rec['action_id'] = (self._get_menu(cr, uid),'Menu')
else:
if not result.get('action_id',True):
result['action_id'] = (self._get_menu(cr, uid),'Menu')
return result
@ -467,6 +477,13 @@ class groups2(osv.osv): ##FIXME: Is there a reason to inherit this object ?
_columns = {
'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'),
}
def unlink(self, cr, uid, ids, context=None):
for record in self.read(cr, uid, ids, ['users'], context=context):
if record['users']:
raise osv.except_osv(_('Warning !'), _('Make sure you have no users linked with the group(s)!'))
return super(groups2, self).unlink(cr, uid, ids, context=context)
groups2()
class res_config_view(osv.osv_memory):

View File

@ -19,7 +19,7 @@
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
"access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1
"access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,1
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,0
"access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0
"access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0
"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
19 access_ir_module_module_group_user ir_module_module group_user model_ir_module_module group_system 1 1 1 1
20 access_ir_module_module_dependency_group_system ir_module_module_dependency group_system model_ir_module_module_dependency group_system 1 1 1 1
21 access_ir_property_group_user ir_property group_user model_ir_property 1 0 0 0
22 access_ir_property_group_user_manager ir_property group_manager model_ir_property base.group_partner_manager 1 1 1 1 0
23 access_ir_report_custom_group_system ir_report_custom group_system model_ir_report_custom 1 0 0 0
24 access_ir_report_custom_fields_group_system ir_report_custom_fields group_system model_ir_report_custom_fields 1 0 0 0
25 access_ir_rule_group_user ir_rule group_user model_ir_rule 1 0 0 0

View File

@ -47,11 +47,12 @@
<rng:define name="assert">
<rng:element name="assert">
<rng:attribute name="model" />
<rng:optional><rng:attribute name="search" /> </rng:optional>
<rng:optional><rng:attribute name="search" /></rng:optional>
<rng:optional><rng:attribute name="count" /></rng:optional>
<rng:optional><rng:attribute name="string" /></rng:optional>
<rng:optional><rng:attribute name="id" /></rng:optional>
<rng:optional><rng:attribute name="severity" /></rng:optional>
<rng:oneOrMore>
<rng:zeroOrMore>
<rng:element name="test">
<rng:attribute name="expr"/>
<rng:choice>
@ -59,7 +60,7 @@
<rng:empty />
</rng:choice>
</rng:element>
</rng:oneOrMore>
</rng:zeroOrMore>
</rng:element>
</rng:define>

View File

@ -382,7 +382,8 @@ class OpenERPDispatcherException(Exception):
class OpenERPDispatcher:
def log(self, title, msg):
Logger().notifyChannel('%s' % title, LOG_DEBUG_RPC, pformat(msg))
if tools.config['log_level'] == logging.DEBUG_RPC:
Logger().notifyChannel('%s' % title, LOG_DEBUG_RPC, pformat(msg))
def dispatch(self, service_name, method, params):
try:

View File

@ -280,8 +280,11 @@ class expression(object):
c = context.copy()
c['active_test'] = False
res_ids = field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)
right = map(lambda x: x[0], res_ids)
self.__exp[i] = (left, 'in', right)
if not res_ids:
self.__exp[i] = ('id','=',0)
else:
right = map(lambda x: x[0], res_ids)
self.__exp[i] = (left, 'in', right)
else:
# other field type
# add the time part to datetime field when it's not there:

View File

@ -39,7 +39,7 @@ from psycopg2 import Binary
import warnings
import tools
from tools.translate import _
def _symbol_set(symb):
if symb == None or symb == False:
@ -748,7 +748,7 @@ class related(function):
ids=[ids]
objlst = obj.browse(cr, uid, ids)
for data in objlst:
t_id=None
t_id = None
t_data = data
relation = obj._name
for i in range(len(self.arg)):

View File

@ -49,6 +49,7 @@ import string
import sys
import time
import traceback
import datetime
import types
import fields
@ -58,6 +59,7 @@ from tools.translate import _
import copy
import sys
import operator
try:
from lxml import etree
@ -86,7 +88,6 @@ def last_day_of_current_month():
def intersect(la, lb):
return filter(lambda x: x in lb, la)
class except_orm(Exception):
def __init__(self, name, value):
self.name = name
@ -276,7 +277,7 @@ class browse_record(object):
else:
new_data[n] = data[n]
self._data[data['id']].update(new_data)
if not name in self._data[self._id]:
#how did this happen?
self.logger.notifyChannel("browse_record", netsvc.LOG_ERROR,
@ -447,7 +448,7 @@ class orm_template(object):
'name': k,
'field_description': f.string.replace("'", " "),
'ttype': f._type,
'relation': f._obj or 'NULL',
'relation': f._obj or '',
'view_load': (f.view_load and 1) or 0,
'select_level': tools.ustr(f.select or 0),
'readonly':(f.readonly and 1) or 0,
@ -544,6 +545,8 @@ class orm_template(object):
return browse_null()
def __export_row(self, cr, uid, row, fields, context=None):
if context is None:
context = {}
def check_type(field_type):
if field_type == 'float':
@ -597,9 +600,9 @@ class orm_template(object):
cols = selection_field(self._inherits)
if cols and cols._type == 'selection':
sel_list = cols.selection
if type(sel_list) == type([]):
r = [x[1] for x in sel_list if r==x[0]][0]
if r and type(sel_list) == type([]):
r = [x[1] for x in sel_list if r==x[0]]
r = r and r[0] or False
if not r:
if f[i] in self._columns:
r = check_type(self._columns[f[i]]._type)
@ -626,7 +629,7 @@ class orm_template(object):
for rr in r :
if isinstance(rr.name, browse_record):
rr = rr.name
rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id])
rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id], context=context)
rr_name = rr_name and rr_name[0] and rr_name[0][1] or ''
dt += tools.ustr(rr_name or '') + ','
data[fpos] = dt[:-1]
@ -639,7 +642,7 @@ class orm_template(object):
i += 1
if i == len(f):
if isinstance(r, browse_record):
r = self.pool.get(r._table_name).name_get(cr, uid, [r.id])
r = self.pool.get(r._table_name).name_get(cr, uid, [r.id], context=context)
r = r and r[0] and r[0][1] or ''
data[fpos] = tools.ustr(r or '')
return [data] + lines
@ -795,12 +798,12 @@ class orm_template(object):
module, xml_id = line[i].rsplit('.', 1)
else:
module, xml_id = current_module, line[i]
id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
res_res_id = ir_model_data_obj.read(cr, uid, [id],
['res_id'])
if res_res_id:
res_id = res_res_id[0]['res_id']
record_id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
ir_model_data = ir_model_data_obj.read(cr, uid, [record_id], ['res_id'])
if ir_model_data:
res_id = ir_model_data[0]['res_id']
else:
raise ValueError('No references to %s.%s' % (module, xml_id))
row[field[-1][:-3]] = res_id or False
continue
if (len(field) == len(prefix)+1) and \
@ -994,7 +997,8 @@ class orm_template(object):
msg = _('Insertion Failed! ' + e[1])
return (-1, res, 'Line ' + str(counter) +' : ' + msg, '' )
#Raising Uncaught exception
raise
return (-1, res, 'Line ' + str(counter) +' : ' + str(e), '' )
for lang in translate:
context2 = context.copy()
context2['lang'] = lang
@ -1003,6 +1007,8 @@ class orm_template(object):
data = pickle.load(file(config.get('import_partial')))
data[filename] = initial_size - len(datas) + original_value
pickle.dump(data, file(config.get('import_partial'),'wb'))
if context.get('defer_parent_store_computation'):
self._parent_store_compute(cr)
cr.commit()
#except Exception, e:
@ -1016,6 +1022,8 @@ class orm_template(object):
#
# TODO: Send a request with the result and multi-thread !
#
if context.get('defer_parent_store_computation'):
self._parent_store_compute(cr)
return (done, 0, 0, 0)
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
@ -1108,8 +1116,7 @@ class orm_template(object):
if getattr(self._columns[f], arg, None):
res[f][arg] = getattr(self._columns[f], arg)
#TODO: optimize
res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US')
res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US', self._columns[f].string)
if res_trans:
res[f]['string'] = res_trans
help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context.get('lang', False) or 'en_US')
@ -1724,7 +1731,8 @@ class orm_template(object):
for lang in langs:
for field in vals:
if field in self._columns:
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
src = self._columns[field].string
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field], src)
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), vals)
if cols:
@ -2137,6 +2145,8 @@ class orm(orm_template):
return (tables, where_clause)
def _parent_store_compute(self, cr):
if not self._parent_store:
return
logger = netsvc.Logger()
logger.notifyChannel('orm', netsvc.LOG_INFO, 'Computing parent left and right for table %s...' % (self._table, ))
def browse_rec(root, pos=0):
@ -2225,8 +2235,8 @@ class orm(orm_template):
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)' % (self._table, ))
if 'parent_right' not in self._columns:
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, ))
if self._columns[self._parent_name].ondelete<>'cascade':
logger.notifyChannel('orm', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name))
if self._columns[self._parent_name].ondelete != 'cascade':
logger.notifyChannel('orm', netsvc.LOG_ERROR, "The column %s on object %s must be set as ondelete='cascade'" % (self._parent_name, self._name))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
cr.commit()
@ -2472,6 +2482,8 @@ class orm(orm_template):
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (self._table,))
create = not bool(cr.fetchone())
cr.commit() # start a new transaction
for (key, con, _) in self._sql_constraints:
conname = '%s_%s' % (self._table, key)
cr.execute("SELECT conname FROM pg_constraint where conname=%s", (conname,))
@ -2481,6 +2493,7 @@ class orm(orm_template):
cr.commit()
except:
logger.notifyChannel('orm', netsvc.LOG_WARNING, 'unable to add \'%s\' constraint on table %s !\n If you want to have it, you should update the records and execute manually:\nALTER table %s ADD CONSTRAINT %s_%s %s' % (con, self._table, self._table, self._table, key, con,))
cr.rollback()
if create:
if hasattr(self, "_sql"):
@ -2491,6 +2504,7 @@ class orm(orm_template):
cr.commit()
if store_compute:
self._parent_store_compute(cr)
cr.commit()
return todo_end
def __init__(self, cr):
@ -2646,11 +2660,16 @@ class orm(orm_template):
for i in range(len(field_value)):
field_value2.append({})
for field2 in field_value[i]:
if obj._columns[field2]._type in ('many2one', 'one2one'):
if field2 in obj._columns.keys() and obj._columns[field2]._type in ('many2one', 'one2one'):
obj2 = self.pool.get(obj._columns[field2]._obj)
if not obj2.search(cr, uid,
[('id', '=', field_value[i][field2])]):
continue
elif field2 in obj._inherit_fields.keys() and obj._inherit_fields[field2][2]._type in ('many2one', 'one2one'):
obj2 = self.pool.get(obj._inherit_fields[field2][2]._obj)
if not obj2.search(cr, uid,
[('id', '=', field_value[i][field2])]):
continue
# TODO add test for many2many and one2many
field_value2[i][field2] = field_value[i][field2]
field_value = field_value2
@ -3107,6 +3126,24 @@ class orm(orm_template):
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
# No direct update of parent_left/right
vals.pop('parent_left', None)
vals.pop('parent_right', None)
parents_changed = []
if self._parent_store and (self._parent_name in vals):
# The parent_left/right computation may take up to
# 5 seconds. No need to recompute the values if the
# parent is the same. Get the current value of the parent
base_query = 'SELECT id FROM %s WHERE id IN %%s AND %s' % \
(self._table, self._parent_name)
params = (tuple(ids),)
parent_val = vals[self._parent_name]
if parent_val:
cr.execute(base_query + " != %s", params + (parent_val,))
else:
cr.execute(base_query + " IS NULL", params)
parents_changed = map(operator.itemgetter(0), cr.fetchall())
upd0 = []
upd1 = []
@ -3196,41 +3233,48 @@ class orm(orm_template):
self.pool.get(table).write(cr, user, nids, v, context)
self._validate(cr, user, ids, context)
# TODO: use _order to set dest at the right position and not first node of parent
if self._parent_store and (self._parent_name in vals):
# TODO: use _order to set dest at the right position and not first node of parent
# We can't defer parent_store computation because the stored function
# fields that are computer may refer (directly or indirectly) to
# parent_left/right (via a child_of domain)
if parents_changed:
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
for id in ids:
# Find Position of the element
if vals[self._parent_name]:
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (vals[self._parent_name],))
else:
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+' is null order by '+(self._parent_order or self._order))
result_p = cr.fetchall()
position = None
for (pleft,pright,pid) in result_p:
if pid == id:
break
position = pright+1
order = self._parent_order or self._order
parent_val = vals[self._parent_name]
if parent_val:
clause, params = '%s=%%s' % (self._parent_name,), (parent_val,)
else:
clause, params = '%s IS NULL' % (self._parent_name,), ()
cr.execute('SELECT parent_right, id FROM %s WHERE %s ORDER BY %s' % (self._table, clause, order), params)
parents = cr.fetchall()
# It's the first node of the parent: position = parent_left+1
if not position:
if not vals[self._parent_name]:
position = 1
else:
cr.execute('select parent_left from '+self._table+' where id=%s', (vals[self._parent_name],))
position = cr.fetchone()[0]+1
# We have the new position !
cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (id,))
pleft,pright = cr.fetchone()
for id in parents_changed:
cr.execute('SELECT parent_left, parent_right FROM %s WHERE id=%%s' % (self._table,), (id,))
pleft, pright = cr.fetchone()
distance = pright - pleft + 1
if position>pleft and position<=pright:
# Find Position of the element
position = None
for (parent_pright, parent_id) in parents:
if parent_id == id:
break
position = parent_pright+1
# It's the first node of the parent
if not position:
if not parent_val:
position = 1
else:
cr.execute('select parent_left from '+self._table+' where id=%s', (parent_val,))
position = cr.fetchone()[0]+1
if pleft < position <= pright:
raise except_orm(_('UserError'), _('Recursivity Detected.'))
if pleft<position:
if pleft < position:
cr.execute('update '+self._table+' set parent_left=parent_left+%s where parent_left>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_left=parent_left+%s, parent_right=parent_right+%s where parent_left>=%s and parent_left<%s', (position-pleft,position-pleft, pleft, pright))
@ -3411,7 +3455,7 @@ class orm(orm_template):
self.check_access_rule(cr, user, [id_new], 'create', context=context)
upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority)
if self._parent_store:
if self._parent_store and not context.get('defer_parent_store_computation'):
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
@ -3639,8 +3683,9 @@ class orm(orm_template):
* '&' (default), '|', '!'
"""
if not context:
if context is None:
context = {}
self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
# compute the where, order by, limit and offset clauses
(qu1, qu2, tables) = self._where_calc(cr, user, args, context=context)
dom = self.pool.get('ir.rule').domain_get(cr, user, self._name, 'read', context=context)
@ -3750,9 +3795,9 @@ class orm(orm_template):
:return: dictionary containing all the field values
"""
if not context:
if context is None:
context = {}
if not default:
if default is None:
default = {}
if 'state' not in default:
if 'state' in self._defaults:
@ -3761,7 +3806,11 @@ class orm(orm_template):
else:
default['state'] = self._defaults['state']
data = self.read(cr, uid, [id], context=context)[0]
context_wo_lang = context
if 'lang' in context:
del context_wo_lang['lang']
data = self.read(cr, uid, [id], context=context_wo_lang)[0]
fields = self.fields_get(cr, uid, context=context)
trans_data=[]
for f in fields:
@ -3796,17 +3845,14 @@ class orm(orm_template):
trans_obj = self.pool.get('ir.translation')
#TODO: optimize translations
trans_name=''
for f in fields:
trans_flag=True
trans_name = ''
if f in self._columns and self._columns[f].translate:
trans_name=self._name+","+f
trans_name = self._name+","+f
elif f in self._inherit_fields and self._inherit_fields[f][2].translate:
trans_name=self._inherit_fields[f][0]+","+f
else:
trans_flag=False
trans_name = self._inherit_fields[f][0] + "," + f
if trans_flag:
if trans_name:
trans_ids = trans_obj.search(cr, uid, [
('name', '=', trans_name),
('res_id','=',data['id'])

View File

@ -253,7 +253,8 @@ class osv(osv_base, orm.orm):
for c in cls.__dict__.get(s, []):
exist = False
for c2 in range(len(new)):
if new[c2][2]==c[2]:
#For _constraints, we should check field and methods as well
if new[c2][2]==c[2] and new[c2][0]==c[0]:
new[c2] = c
exist = True
break

View File

@ -21,8 +21,8 @@
##############################################################################
name = 'openerp-server'
version = '5.2dev'
major_version = '5.2'
version = '6.0dev'
major_version = '6.0'
description = 'OpenERP Server'
long_desc = '''\
OpenERP is a complete ERP and CRM. The main features are accounting (analytic

View File

@ -36,6 +36,7 @@ from pychart import *
import misc
import cStringIO
from lxml import etree
from tools.translate import _
class external_pdf(render.render):
def __init__(self, pdf):

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/>.
#
##############################################################################
@ -35,7 +35,7 @@ class report(object):
for node in root_node:
if node.tag == etree.Comment:
continue
if node.text:
if node.text or node.tail:
def _sub3(txt):
n = node
while n.tag != txt.group(2):
@ -71,9 +71,9 @@ class report(object):
n = n.getparent()
n.set('rml_loop', txt.group(2))
return '[['+txt.group(1)+"''"+txt.group(4)+']]'
t = _regex1.sub(_sub1, node.text)
t = _regex1.sub(_sub1, node.text or node.tail)
if t == " ":
t = _regex11.sub(_sub1, node.text)
t = _regex11.sub(_sub1, node.text or node.tail)
t = _regex3.sub(_sub3, t)
node.text = _regex2.sub(_sub2, t)
self.preprocess_rml(node,type)

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/>.
#
##############################################################################
@ -52,13 +52,20 @@ class _rml_styles(object,):
def __init__(self, nodes, localcontext):
self.localcontext = localcontext
self.styles = {}
self.styles_obj = {}
self.names = {}
self.table_styles = {}
self.default_style = reportlab.lib.styles.getSampleStyleSheet()
for node in nodes:
for style in node.findall('blockTableStyle'):
self.table_styles[style.get('id')] = self._table_style_get(style)
for style in node.findall('paraStyle'):
self.styles[style.get('name')] = self._para_style_update(style)
sname = style.get('name')
self.styles[sname] = self._para_style_update(style)
self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname])
for variable in node.findall('initialize'):
for name in variable.findall('name'):
self.names[ name.get('id')] = name.get('value')
@ -126,17 +133,19 @@ class _rml_styles(object,):
def para_style_get(self, node):
style = False
if node.get('style'):
if node.get('style') in self.styles:
styles = reportlab.lib.styles.getSampleStyleSheet()
sname = node.get('style')
style = reportlab.lib.styles.ParagraphStyle(sname, styles["Normal"], **self.styles[sname])
sname = node.get('style')
if sname:
if sname in self.styles_obj:
style = self.styles_obj[sname]
else:
sys.stderr.write('Warning: style not found, %s - setting default!\n' % (node.get('style'),) )
if not style:
styles = reportlab.lib.styles.getSampleStyleSheet()
style = styles['Normal']
style.__dict__.update(self._para_style_update(node))
style = self.default_style['Normal']
para_update = self._para_style_update(node)
if para_update:
# update style only is necessary
style = copy.deepcopy(style)
style.__dict__.update(para_update)
return style
class _rml_doc(object):
@ -167,7 +176,7 @@ class _rml_doc(object):
from reportlab.lib.fonts import addMapping
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont(fontname, filename ))
if (mode == 'all'):
addMapping(face, 0, 0, fontname) #normal
@ -417,11 +426,11 @@ class _rml_canvas(object):
self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
def setFont(self, node):
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import pdfmetrics
fname = node.get('name')
#TODO : other fonts should be supported
#TODO : other fonts should be supported
if fname not in pdfmetrics.standardFonts:
fname = self.canvas._fontname
fname = self.canvas._fontname
return self.canvas.setFont(fname, utils.unit_get(node.get('size')))
def render(self, node):
@ -565,7 +574,7 @@ class _rml_flowable(object):
def _illustration(self, node):
class Illustration(platypus.flowables.Flowable):
def __init__(self, node, localcontext, styles, self2):
self.localcontext = localcontext
self.localcontext = localcontext.copy()
self.node = node
self.styles = styles
self.width = utils.unit_get(node.get('width'))

View File

@ -441,8 +441,8 @@ class report_sxw(report_rml, preprocess.report):
rml_parser.set_context(objs, data, ids, report_xml.report_type)
processed_rml = etree.XML(rml)
if report_xml.header:
rml_parser._add_header(processed_rml)
processed_rml = self.preprocess_rml(processed_rml,report_xml.report_type)
rml_parser._add_header(processed_rml, self.header)
processed_rml = self.preprocess_rml(processed_rml,report_xml.report_type)
if rml_parser.logo:
logo = base64.decodestring(rml_parser.logo)
create_doc = self.generators[report_xml.report_type]

View File

@ -283,8 +283,8 @@ class db(netsvc.ExportService):
## Not True: in fact, check if connection to database is possible. The database may exists
return bool(sql_db.db_connect(db_name))
def exp_list(self):
if not tools.config['list_db']:
def exp_list(self, document=False):
if not tools.config['list_db'] and not document:
raise Exception('AccessDenied')
db = sql_db.db_connect('template1')

View File

@ -123,7 +123,6 @@ class configmanager(object):
parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=self._LOGLEVELS.keys(),
help="specify the level at which a failed assertion will stop the server. Accepted values: %s" % (self._LOGLEVELS.keys(),))
parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='deprecated since v6.0, replaced by module decimal_precision')
parser.add_option('--no-database-list', action="store_false", dest='list_db', default=True, help="disable the ability to return the list of databases")
if self.has_ssl:
group = optparse.OptionGroup(parser, "SSL Configuration")
@ -136,7 +135,7 @@ class configmanager(object):
default="server.pkey",
help="specify the private key file for the SSL connection")
parser.add_option_group(group)
# Testing Group
group = optparse.OptionGroup(parser, "Testing Configuration")
group.add_option("--test-disable", action="store_true", dest="test_disable",
@ -144,7 +143,7 @@ class configmanager(object):
group.add_option("--test-commit", action="store_true", dest="test_commit",
default=False, help="Commit database changes performed by tests.")
parser.add_option_group(group)
# Logging Group
group = optparse.OptionGroup(parser, "Logging Configuration")
group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
@ -161,8 +160,7 @@ class configmanager(object):
group.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email')
group.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
group.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port', type="int")
if self.has_ssl:
group.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
group.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
group.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
group.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
parser.add_option_group(group)
@ -199,6 +197,13 @@ class configmanager(object):
action="callback", callback=self._check_addons_path, nargs=1, type="string")
parser.add_option_group(group)
security = optparse.OptionGroup(parser, 'Security-related options')
security.add_option('--no-database-list', action="store_false", dest='list_db', default=True, help="disable the ability to return the list of databases")
security.add_option('--enable-code-actions', action='store_true',
dest='server_actions_allow_code', default=False,
help='Enables server actions of state "code". Warning, this is a security risk.')
parser.add_option_group(security)
def parse_config(self):
(opt, args) = self.parser.parse_args()
@ -244,13 +249,13 @@ class configmanager(object):
self.options['pidfile'] = False
keys = ['interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout',
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout','smtp_ssl',
'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path',
'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',]
if self.has_ssl:
keys.extend(['smtp_ssl', 'secure_cert_file', 'secure_pkey_file'])
keys.extend(['secure_cert_file', 'secure_pkey_file'])
keys.append('secure')
for arg in keys:
@ -258,7 +263,8 @@ class configmanager(object):
self.options[arg] = getattr(opt, arg)
keys = ['language', 'translate_out', 'translate_in', 'debug_mode',
'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog', 'list_db']
'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog',
'list_db', 'server_actions_allow_code']
if self.has_ssl and not self.options['secure']:
keys.append('secure')

View File

@ -26,11 +26,9 @@ import os.path
import pickle
import re
import sys
import time
from datetime import datetime
from lxml import etree
import ir
import misc
import netsvc
@ -79,6 +77,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
return f_val
a_eval = node.get('eval','')
if a_eval:
import time
idref2 = idref.copy()
idref2['time'] = time
idref2['DateTime'] = datetime
@ -253,6 +252,14 @@ form: module.record_id""" % (xml_id,)
self.pool.get(d_model).unlink(cr, self.uid, ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids)
def _remove_ir_values(self, cr, name, value, model):
ir_value_ids = self.pool.get('ir.values').search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)])
if ir_value_ids:
self.pool.get('ir.values').unlink(cr, self.uid, ir_value_ids)
self.pool.get('ir.model.data')._unlink(cr, self.uid, 'ir.values', ir_value_ids)
return True
def _tag_report(self, cr, rec, data_node=None):
res = {}
for dest,f in (('name','string'),('model','model'),('report_name','name')):
@ -262,16 +269,17 @@ form: module.record_id""" % (xml_id,)
if rec.get(field):
res[dest] = rec.get(field).encode('utf8')
if rec.get('auto'):
res['auto'] = eval(rec.get('auto'))
res['auto'] = eval(rec.get('auto','False'))
if rec.get('sxw'):
sxw_content = misc.file_open(rec.get('sxw')).read()
res['report_sxw_content'] = sxw_content
if rec.get('header'):
res['header'] = eval(rec.get('header'))
res['header'] = eval(rec.get('header','False'))
if rec.get('report_type'):
res['report_type'] = rec.get('report_type')
res['multi'] = rec.get('multi') and eval(rec.get('multi'))
res['multi'] = rec.get('multi') and eval(rec.get('multi','False'))
xml_id = rec.get('id','').encode('utf8')
self._test_xml_id(xml_id)
@ -291,12 +299,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if not rec.get('menu') or eval(rec.get('menu','')):
if not rec.get('menu') or eval(rec.get('menu','False')):
keyword = str(rec.get('keyword', 'client_print_multi'))
keys = [('action',keyword),('res_model',res['model'])]
value = 'ir.actions.report.xml,'+str(id)
replace = rec.get('replace', True)
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and eval(rec.get('menu','False'))==False:
# Special check for report having attribute menu=False on update
value = 'ir.actions.report.xml,'+str(id)
self._remove_ir_values(cr, res['name'], value, res['model'])
return False
def _tag_function(self, cr, rec, data_node=None):
@ -313,7 +325,7 @@ form: module.record_id""" % (xml_id,)
name = rec.get("name",'').encode('utf8')
xml_id = rec.get('id','').encode('utf8')
self._test_xml_id(xml_id)
multi = rec.get('multi','') and eval(rec.get('multi',''))
multi = rec.get('multi','') and eval(rec.get('multi','False'))
res = {'name': string, 'wiz_name': name, 'multi': multi, 'model': model}
if rec.get('groups'):
@ -332,12 +344,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.get('menu') or eval(rec.get('menu',''))) and id:
if (not rec.get('menu') or eval(rec.get('menu','False'))) and id:
keyword = str(rec.get('keyword','') or 'client_action_multi')
keys = [('action',keyword),('res_model',model)]
value = 'ir.actions.wizard,'+str(id)
replace = rec.get("replace",'') or True
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False):
# Special check for wizard having attribute menu=False on update
value = 'ir.actions.wizard,'+str(id)
self._remove_ir_values(cr, string, value, model)
def _tag_url(self, cr, rec, data_node=None):
url = rec.get("string",'').encode('utf8')
@ -351,12 +367,16 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.get('menu') or eval(rec.get('menu',''))) and id:
if (not rec.get('menu') or eval(rec.get('menu','False'))) and id:
keyword = str(rec.get('keyword','') or 'client_action_multi')
keys = [('action',keyword)]
value = 'ir.actions.url,'+str(id)
replace = rec.get("replace",'') or True
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id)
elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False):
# Special check for URL having attribute menu=False on update
value = 'ir.actions.url,'+str(id)
self._remove_ir_values(cr, url, value, "ir.actions.url")
def _tag_act_window(self, cr, rec, data_node=None):
name = rec.get('name','').encode('utf-8')
@ -379,11 +399,12 @@ form: module.record_id""" % (xml_id,)
uid = self.uid
# def ref() added because , if context has ref('id') eval wil use this ref
active_id=str("active_id") # for further reference in client/bin/tools/__init__.py
active_id = str("active_id") # for further reference in client/bin/tools/__init__.py
def ref(str_id):
return self.id_get(cr, None, str_id)
context = eval(context)
# domain = eval(domain) # XXX need to test this line -> uid, active_id, active_ids, ...
res = {
'name': name,

View File

@ -820,6 +820,22 @@ class cache(object):
def to_xml(s):
return s.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
def get_encodings():
yield 'utf8'
from locale import getpreferredencoding
prefenc = getpreferredencoding()
if prefenc:
yield prefenc
prefenc = {
'latin1': 'latin9',
'iso-8859-1': 'iso8859-15',
'cp1252': '1252',
}.get(prefenc.lower())
if prefenc:
yield prefenc
def ustr(value):
"""This method is similar to the builtin `str` method, except
it will return Unicode string.
@ -829,29 +845,25 @@ def ustr(value):
@rtype: unicode
@return: unicode string
"""
orig = value
if isinstance(value, Exception):
return exception_to_unicode(value)
if isinstance(value, unicode):
return value
if hasattr(value, '__unicode__'):
try:
return unicode(value)
if not isinstance(value, str):
value = str(value)
try: # first try utf-8
return unicode(value, 'utf-8')
except:
pass
try: # then extened iso-8858
return unicode(value, 'iso-8859-15')
except:
pass
for ln in get_encodings():
try:
return unicode(value, ln)
except:
pass
raise UnicodeError('unable de to convert %r' % (orig,))
# else use default system locale
from locale import getlocale
return unicode(value, getlocale()[1])
def exception_to_unicode(e):
if (sys.version_info[:2] < (2,6)) and hasattr(e, 'message'):
@ -914,7 +926,7 @@ def get_languages():
'fr_BE': u'French (BE) / Français (BE)',
'fr_CH': u'French (CH) / Français (CH)',
'fr_FR': u'French / Français',
'gl_ES': u'Galician / Spain',
'gl_ES': u'Galician / Galego',
'gu_IN': u'Gujarati / India',
'hi_IN': u'Hindi / India',
'hr_HR': u'Croatian / hrvatski jezik',
@ -939,8 +951,8 @@ def get_languages():
'ro_RO': u'Romanian / limba română',
'ru_RU': u'Russian / русский язык',
'si_LK': u'Sinhalese / Sri Lanka',
'sk_SK': u'Slovak / Slovakia',
'sl_SL': u'Slovenian / slovenščina',
'sl_SI': u'Slovenian / slovenščina',
'sk_SK': u'Slovak / Slovenský jazyk',
'sq_AL': u'Albanian / Shqipëri',
'sr_RS': u'Serbian / Serbia',
'sv_SE': u'Swedish / svenska',

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/>.
#
##############################################################################
@ -596,23 +596,30 @@ def trans_generate(lang, modules, dbname=None):
push_translation(module, 'model', name, xml_name, encode(trad))
# parse source code for _() calls
def get_module_from_path(path,mod_paths=None):
if not mod_paths:
# First, construct a list of possible paths
def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
mod_paths=[def_path]
for adp in ad_paths:
mod_paths.append(adp)
if not adp.startswith('/'):
mod_paths.append(os.path.join(def_path,adp))
elif adp.startswith(def_path):
mod_paths.append(adp[len(def_path)+1:])
for mp in mod_paths:
if path.startswith(mp) and (os.path.dirname(path) != mp):
path = path[len(mp)+1:]
return path.split(os.path.sep)[0]
def get_module_from_path(path, mod_paths=None):
# if not mod_paths:
## First, construct a list of possible paths
# def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
# ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
# mod_paths=[def_path]
# for adp in ad_paths:
# mod_paths.append(adp)
# if not adp.startswith('/'):
# mod_paths.append(os.path.join(def_path,adp))
# elif adp.startswith(def_path):
# mod_paths.append(adp[len(def_path)+1:])
# for mp in mod_paths:
# if path.startswith(mp) and (os.path.dirname(path) != mp):
# path = path[len(mp)+1:]
# return path.split(os.path.sep)[0]
path_dir = os.path.dirname(path[1:])
if path_dir:
if os.path.exists(os.path.join(tools.config['addons_path'],path[1:])):
return path.split(os.path.sep)[1]
else:
root_addons = os.path.join(tools.config['root_path'], 'addons')
if os.path.exists(os.path.join(root_addons,path[1:])):
return path.split(os.path.sep)[1]
return 'base' # files that are not in a module are considered as being in 'base' module
modobj = pool.get('ir.module.module')
@ -699,6 +706,11 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
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,
@ -706,9 +718,10 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, 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' : str(locale.localeconv()['decimal_point']).replace('\xa0', '\xc2\xa0'),
'thousands_sep' : str(locale.localeconv()['thousands_sep']).replace('\xa0', '\xc2\xa0'),
'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:
@ -767,7 +780,7 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
# the same source
obj = pool.get(model)
if obj:
if not field in obj._columns:
if field not in obj.fields_get_keys(cr, uid):
continue
ids = obj.search(cr, uid, [(field, '=', dic['src'])])

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ formats=rpm
[bdist_rpm]
# release must exactly match 'release' as set in bin/release.py
release=3
release=10
requires=python >= 2.4
#build-requires=python-devel >= 2.3

View File

@ -44,7 +44,7 @@ sys.path.append(join(os.path.abspath(os.path.dirname(__file__)), "bin"))
execfile(join('bin', 'release.py'))
if sys.argv[1] == 'bdist_rpm':
if 'bdist_rpm' in sys.argv:
version = version.split('-')[0]
# get python short version
@ -177,11 +177,14 @@ options = {
"compressed": 1,
"optimize": 2,
"dist_dir": 'dist',
"packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "encodings",
"dateutil", "wizard", "pychart", "PIL", "pyparsing",
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "yaml", "pywebdav"],
"packages": [
"lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml", "xml.dom", "xml.xpath",
"encodings", "dateutil", "wizard", "pychart", "PIL", "pyparsing",
"pydot", "asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "select", "mako", "poplib",
"imaplib", "smtplib", "email", "yaml","pywebdav",
],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}
}