<menuitem id="base.menu_sales" parent="base.menu_base_partner" name="Sales" sequence="1" />
<menuitem id="menu_base_config" parent="menu_base_partner" name="Configuration" sequence="30" groups="group_system"/>
- <menuitem id="menu_config_address_book" parent="menu_base_config" name="Address Book" sequence="40" groups="group_system"/>
+ <menuitem id="menu_config_address_book" parent="menu_base_config" name="Address Book" sequence="40" groups="group_system"/>
<!-- Partner Titles -->
<record id="view_partner_title_tree" model="ir.ui.view">
<field eval="8" name="priority"/>
<field name="arch" type="xml">
<tree string="Contacts">
- <field name="name"/>
+ <field name="display_name"/>
<field name="function" invisible="1"/>
<field name="phone"/>
<field name="email"/>
<group>
<field name="category_id" widget="many2many_tags" placeholder="Tags..."/>
<field name="function" placeholder="e.g. Sales Director"/>
- <field name="email" required="context.get('force_email', False)"/>
+ <field name="user_ids" invisible="1"/>
+ <field name="email" widget="email" required="context.get('force_email', False)" attrs="{'required': [('user_ids','!=', [])]}"/>
<field name="phone"/>
<field name="mobile"/>
</group>
<form string="Partners" version="7.0">
<sheet>
<field name="image" widget='image' class="oe_left oe_avatar" options='{"preview_image": "image_medium", "size": [90, 90]}'/>
- <div class="oe_title">
+ <div class="oe_title oe_left">
<div class="oe_edit_only">
<label for="name"/> (
<field name="is_company" on_change="onchange_type(is_company)" class="oe_inline"/> <label for="is_company" string="Is a Company?"/>)
<field name="phone" placeholder="e.g. +32.81.81.37.00"/>
<field name="mobile"/>
<field name="fax"/>
- <field name="email" widget="email"/>
+ <field name="user_ids" invisible="1"/>
+ <field name="email" widget="email" attrs="{'required': [('user_ids','!=', [])]}"/>
<field name="title" domain="[('domain', '=', 'contact')]"
options='{"no_open": True}' attrs="{'invisible': [('is_company','=', True)]}" />
</group>
</form>
</field>
</page>
- <page string="Internal Notes">
+ <page name='internal_notes' string="Internal Notes">
<field name="comment" placeholder="Put an internal note..."/>
</page>
- <page string="Sales & Purchases">
+ <page name='sales_purchases' string="Sales & Purchases">
<group>
<group>
- <field name="user_id"/>
+ <field name="user_id"
+ context="{'default_groups_ref': ['base.group_partner_manager']}"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<group>
</group>
</group>
</page>
- <!-- The History page becomes visible as soon as there is something to display inside -->
- <page string="History" name="page_history" invisible="True">
- </page>
</notebook>
</sheet>
</form>
<field name="arch" type="xml">
<search string="Search Partner">
<field name="name"
- filter_domain="['|','|',('name','ilike',self),('parent_id','ilike',self),('ref','=',self)]"/>
+ filter_domain="['|','|',('display_name','ilike',self),('ref','=',self),('email','ilike',self)]"/>
<filter help="My Partners" icon="terp-personal+" domain="[('user_id','=',uid)]"/>
<separator/>
<filter string="Persons" name="type_person" domain="[('is_company','=',0)]"/>
<separator/>
<field name="category_id" string="Tag" filter_domain="[('category_id','ilike', self)]"/>
<field name="user_id"/>
- <field name="parent_id" domain="[('is_company','=',1)]" filter_domain="[('parent_id','child_of',[self])]"/>
+ <field name="parent_id" domain="[('is_company','=',1)]" operator="child_of"/>
<group expand="0" string="Group By...">
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by' : 'user_id'}" />
<filter string="Company" context="{'group_by': 'parent_id'}"/>
<field name="arch" type="xml">
<kanban>
<field name="color"/>
- <field name="name"/>
+ <field name="display_name"/>
<field name="title"/>
<field name="email"/>
<field name="parent_id"/>
</t>
</a>
<div class="oe_kanban_details">
- <h4 class="oe_partner_heading"><a type="open"><field name="name"/></a></h4>
+ <h4 class="oe_partner_heading"><a type="open"><field name="display_name"/></a></h4>
<div class="oe_kanban_partner_categories"/>
<div class="oe_kanban_partner_links"/>
<ul>
<field name="view_id" ref="view_partner_tree"/>
<field name="act_window_id" ref="action_partner_form"/>
</record>
- <menuitem id="menu_partner_form" parent="base.menu_sales" action="action_partner_form" sequence="1"/>
+ <menuitem id="menu_partner_form" parent="base.menu_sales" action="action_partner_form" sequence="2"/>
<record id="action_partner_customer_form" model="ir.actions.act_window">
<field name="name">Customers</field>
<!-- Categories -->
<record id="view_partner_category_form" model="ir.ui.view">
- <field name="name">Partner Categories</field>
+ <field name="name">Partner Tags</field>
<field name="model">res.partner.category</field>
<field name="arch" type="xml">
- <form string="Partner Category" version="7.0">
+ <form string="Partner Tag" version="7.0">
<group col="4">
<field name="name"/>
<field name="active"/>
</field>
</record>
<record id="view_partner_category_list" model="ir.ui.view">
- <field name="name">Partner Categories</field>
+ <field name="name">Partner Tags</field>
<field name="model">res.partner.category</field>
<field eval="6" name="priority"/>
<field name="arch" type="xml">
- <tree string="Partner Categories">
+ <tree string="Partner Tags">
<field name="complete_name"/>
</tree>
</field>
<field name="model">res.partner.category</field>
<field name="field_parent">child_ids</field>
<field name="arch" type="xml">
- <tree toolbar="1" string="Partner Categories">
+ <tree toolbar="1" string="Partner Tags">
<field name="name"/>
</tree>
</field>
-->
<record id="action_partner_by_category" model="ir.actions.act_window">
- <field name="name">Partner Categories</field>
+ <field name="name">Partner Tags</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record id="action_partner_category_form" model="ir.actions.act_window">
- <field name="name">Partner Categories</field>
+ <field name="name">Partner Tags</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner.category</field>
<field name="view_type">form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
- Click to create a new partner category.
+ Click to create a new partner tags.
</p><p>
- Manage the partner categories in order to better classify them for tracking and analysis purposes.
- A partner may belong to several categories and categories have a hierarchy structure: a partner belonging to a category also belong to his parent category.
+ Manage the partner tags to better classify them for tracking and analysis purposes.
+ A partner may have several tags and tags have a hierarchical structure: a partner with a tag has also the parent tags.
</p>
</field>
</record>
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
+# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
import openerp
from openerp import SUPERUSER_ID
-from openerp import pooler, tools
+from openerp import tools
import openerp.exceptions
- from openerp.osv import fields,osv
+ from openerp.osv import fields,osv, expression
from openerp.osv.orm import browse_record
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
-class groups(osv.osv):
+#----------------------------------------------------------
+# Basic res.groups and res.users
+#----------------------------------------------------------
+
+class res_groups(osv.osv):
_name = "res.groups"
_description = "Access Groups"
_rec_name = 'full_name'
+ _order = 'name'
def _get_full_name(self, cr, uid, ids, field, arg, context=None):
res = {}
def _search_group(self, cr, uid, obj, name, args, context=None):
operand = args[0][2]
operator = args[0][1]
- values = operand.split('/')
- group_name = values[0]
- where = [('name', operator, group_name)]
- if len(values) > 1:
- application_name = values[0]
- group_name = values[1]
- where = ['|',('category_id.name', operator, application_name)] + where
+ lst = True
+ if isinstance(operand, bool):
+ domains = [[('name', operator, operand)], [('category_id.name', operator, operand)]]
+ if operator in expression.NEGATIVE_TERM_OPERATORS == (not operand):
+ return expression.AND(domains)
+ else:
+ return expression.OR(domains)
+ if isinstance(operand, basestring):
+ lst = False
+ operand = [operand]
+ where = []
+ for group in operand:
+ values = filter(bool, group.split('/'))
+ group_name = values.pop().strip()
+ category_name = values and '/'.join(values).strip() or group_name
+ group_domain = [('name', operator, lst and [group_name] or group_name)]
+ category_domain = [('category_id.name', operator, lst and [category_name] or category_name)]
+ if operator in expression.NEGATIVE_TERM_OPERATORS and not values:
+ category_domain = expression.OR([category_domain, [('category_id', '=', False)]])
+ if (operator in expression.NEGATIVE_TERM_OPERATORS) == (not values):
+ sub_where = expression.AND([group_domain, category_domain])
+ else:
+ sub_where = expression.OR([group_domain, category_domain])
+ if operator in expression.NEGATIVE_TERM_OPERATORS:
+ where = expression.AND([where, sub_where])
+ else:
+ where = expression.OR([where, sub_where])
return where
_columns = {
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
# add explicit ordering if search is sorted on full_name
if order and order.startswith('full_name'):
- ids = super(groups, self).search(cr, uid, args, context=context)
+ ids = super(res_groups, self).search(cr, uid, args, context=context)
gs = self.browse(cr, uid, ids, context)
gs.sort(key=lambda g: g.full_name, reverse=order.endswith('DESC'))
gs = gs[offset:offset+limit] if limit else gs[offset:]
return map(int, gs)
- return super(groups, self).search(cr, uid, args, offset, limit, order, context, count)
+ return super(res_groups, self).search(cr, uid, args, offset, limit, order, context, count)
def copy(self, cr, uid, id, default=None, context=None):
group_name = self.read(cr, uid, [id], ['name'])[0]['name']
default.update({'name': _('%s (copy)')%group_name})
- return super(groups, self).copy(cr, uid, id, default, context)
+ return super(res_groups, self).copy(cr, uid, id, default, context)
def write(self, cr, uid, ids, vals, context=None):
if 'name' in vals:
if vals['name'].startswith('-'):
raise osv.except_osv(_('Error'),
_('The name of the group can not start with "-"'))
- res = super(groups, self).write(cr, uid, ids, vals, context=context)
- self.pool.get('ir.model.access').call_cache_clearing_methods(cr)
+ res = super(res_groups, self).write(cr, uid, ids, vals, context=context)
+ self.pool['ir.model.access'].call_cache_clearing_methods(cr)
return res
-groups()
-
class res_users(osv.osv):
""" User class. A res.users record models an OpenERP user and is different
from an employee.
deprecated='Use the email field instead of user_email. This field will be removed with OpenERP 7.1.'),
}
- def on_change_company_id(self, cr, uid, ids, company_id):
- return {'warning' : {
- 'title': _("Company Switch Warning"),
- 'message': _("Please keep in mind that documents currently displayed may not be relevant after switching to another company. If you have unsaved changes, please make sure to save and close all forms before switching to a different company. (You can click on Cancel in the User Preferences now)"),
- }
- }
+ def on_change_login(self, cr, uid, ids, login, context=None):
+ if login and tools.single_email_re.match(login):
+ return {'value': {'email': login}}
+ return {}
def onchange_state(self, cr, uid, ids, state_id, context=None):
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
partner.onchange_type method, but applied to the user object.
"""
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
- return self.pool.get('res.partner').onchange_type(cr, uid, partner_ids, is_company, context=context)
+ return self.pool['res.partner'].onchange_type(cr, uid, partner_ids, is_company, context=context)
def onchange_address(self, cr, uid, ids, use_parent_address, parent_id, context=None):
""" Wrapper on the user.partner onchange_address, because some calls to the
partner.onchange_type method, but applied to the user object.
"""
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)]
- return self.pool.get('res.partner').onchange_address(cr, uid, partner_ids, use_parent_address, parent_id, context=context)
+ return self.pool['res.partner'].onchange_address(cr, uid, partner_ids, use_parent_address, parent_id, context=context)
def _check_company(self, cr, uid, ids, context=None):
return all(((this.company_id in this.company_ids) or not this.company_ids) for this in self.browse(cr, uid, ids, context))
def _get_company(self,cr, uid, context=None, uid2=False):
if not uid2:
uid2 = uid
- user = self.pool.get('res.users').read(cr, uid, uid2, ['company_id'], context)
+ user = self.pool['res.users'].read(cr, uid, uid2, ['company_id'], context)
company_id = user.get('company_id', False)
return company_id and company_id[0] or False
'company_id': _get_company,
'company_ids': _get_companies,
'groups_id': _get_group,
- 'image': lambda self, cr, uid, ctx={}: self.pool.get('res.partner')._get_default_image(cr, uid, False, ctx, colorize=True),
+ 'image': lambda self, cr, uid, ctx={}: self.pool['res.partner']._get_default_image(cr, uid, False, ctx, colorize=True),
}
# User can write on a few of his own fields (but not his groups for example)
uid = SUPERUSER_ID
result = super(res_users, self).read(cr, uid, ids, fields=fields, context=context, load=load)
- canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False)
+ canwrite = self.pool['ir.model.access'].check(cr, uid, 'res.users', 'write', False)
if not canwrite:
if isinstance(ids, (int, long)):
result = override_password(result)
if user.partner_id.company_id and user.partner_id.company_id.id != values['company_id']:
user.partner_id.write({'company_id': user.company_id.id})
# clear caches linked to the users
- self.pool.get('ir.model.access').call_cache_clearing_methods(cr)
- clear = partial(self.pool.get('ir.rule').clear_cache, cr)
+ self.pool['ir.model.access'].call_cache_clearing_methods(cr)
+ clear = partial(self.pool['ir.rule'].clear_cache, cr)
map(clear, ids)
db = cr.dbname
if db in self._uid_cache:
return result
def action_get(self, cr, uid, context=None):
- dataobj = self.pool.get('ir.model.data')
+ dataobj = self.pool['ir.model.data']
data_id = dataobj._get_id(cr, SUPERUSER_ID, 'base', 'action_res_users_my')
return dataobj.browse(cr, uid, data_id, context=context).res_id
if not password:
return False
user_id = False
- cr = pooler.get_db(db).cursor()
+ cr = self.pool.db.cursor()
try:
# autocommit: our single update request will be performed atomically.
# (In this way, there is no opportunity to have two transactions
# Successfully logged in as admin!
# Attempt to guess the web base url...
if user_agent_env and user_agent_env.get('base_location'):
- cr = pooler.get_db(db).cursor()
+ cr = self.pool.db.cursor()
try:
base = user_agent_env['base_location']
- ICP = self.pool.get('ir.config_parameter')
+ ICP = self.pool['ir.config_parameter']
if not ICP.get_param(cr, uid, 'web.base.url.freeze'):
ICP.set_param(cr, uid, 'web.base.url', base)
cr.commit()
raise openerp.exceptions.AccessDenied()
if self._uid_cache.get(db, {}).get(uid) == passwd:
return
- cr = pooler.get_db(db).cursor()
+ cr = self.pool.db.cursor()
try:
self.check_credentials(cr, uid, passwd)
if self._uid_cache.has_key(db):
(uid, module, ext_id))
return bool(cr.fetchone())
-
-#
-# Extension of res.groups and res.users with a relation for "implied" or
-# "inherited" groups. Once a user belongs to a group, it automatically belongs
-# to the implied groups (transitively).
+#----------------------------------------------------------
+# Implied groups
#
+# Extension of res.groups and res.users with a relation for "implied"
+# or "inherited" groups. Once a user belongs to a group, it
+# automatically belongs to the implied groups (transitively).
+#----------------------------------------------------------
class cset(object):
""" A cset (constrained set) is a set of elements that may be constrained to
return res
-
class groups_implied(osv.osv):
_inherit = 'res.groups'
if groups:
# delegate addition of groups to add implied groups
self.write(cr, uid, [user_id], {'groups_id': groups}, context)
+ self.pool['ir.ui.view'].clear_cache()
return user_id
def write(self, cr, uid, ids, values, context=None):
gs = set(concat([g.trans_implied_ids for g in user.groups_id]))
vals = {'groups_id': [(4, g.id) for g in gs]}
super(users_implied, self).write(cr, uid, [user.id], vals, context)
+ self.pool['ir.ui.view'].clear_cache()
return res
+#----------------------------------------------------------
+# Vitrual checkbox and selection for res.user form view
#
# Extension of res.groups and res.users for the special groups view in the users
# form. This extension presents groups with selection and boolean widgets:
# any of ID1, ..., IDk is in 'groups_id'
# - selection field 'sel_groups_ID1_..._IDk' is ID iff
# ID is in 'groups_id' and ID is maximal in the set {ID1, ..., IDk}
+#----------------------------------------------------------
def name_boolean_group(id): return 'in_group_' + str(id)
def name_boolean_groups(ids): return 'in_groups_' + '_'.join(map(str, ids))
return yes, nos
-
class groups_view(osv.osv):
_inherit = 'res.groups'
def update_user_groups_view(self, cr, uid, context=None):
# the view with id 'base.user_groups_view' inherits the user form view,
# and introduces the reified group fields
- view = self.get_user_groups_view(cr, uid, context)
- if view:
+ # we have to try-catch this, because at first init the view does not exist
+ # but we are already creating some basic groups
+ view = self.pool['ir.model.data'].xmlid_to_object(cr, SUPERUSER_ID, 'base.user_groups_view', context=context)
+ if view and view.exists() and view._table_name == 'ir.ui.view':
xml1, xml2 = [], []
xml1.append(E.separator(string=_('Application'), colspan="4"))
for app, kind, gs in self.get_groups_by_application(cr, uid, context):
view.write({'arch': xml_content})
return True
- def get_user_groups_view(self, cr, uid, context=None):
- try:
- view = self.pool.get('ir.model.data').get_object(cr, SUPERUSER_ID, 'base', 'user_groups_view', context)
- assert view and view._table_name == 'ir.ui.view'
- except Exception:
- view = False
- return view
-
def get_application_groups(self, cr, uid, domain=None, context=None):
return self.search(cr, uid, domain or [])
fields1 = (fields + ['groups_id']) if group_fields else fields
values = super(users_view, self).default_get(cr, uid, fields1, context)
self._get_reified_groups(group_fields, values)
+
+ # add "default_groups_ref" inside the context to set default value for group_id with xml values
+ if 'groups_id' in fields and isinstance(context.get("default_groups_ref"), list):
+ groups = []
+ ir_model_data = self.pool.get('ir.model.data')
+ for group_xml_id in context["default_groups_ref"]:
+ group_split = group_xml_id.split('.')
+ if len(group_split) != 2:
+ raise osv.except_osv(_('Invalid context value'), _('Invalid context default_groups_ref value (model.name_id) : "%s"') % group_xml_id)
+ try:
+ temp, group_id = ir_model_data.get_object_reference(cr, uid, group_split[0], group_split[1])
+ except ValueError:
+ group_id = False
+ groups += [group_id]
+ values['groups_id'] = groups
return values
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
- if not fields:
- fields = self.fields_get(cr, uid, context=context).keys()
- group_fields, fields = partition(is_reified_group, fields)
- if not 'groups_id' in fields:
+ fields_get = fields if fields is not None else self.fields_get(cr, uid, context=context).keys()
+ group_fields, _ = partition(is_reified_group, fields_get)
+
+ inject_groups_id = group_fields and fields and 'groups_id' not in fields
+ if inject_groups_id:
fields.append('groups_id')
res = super(users_view, self).read(cr, uid, ids, fields, context=context, load=load)
- if res:
+
+ if res and group_fields:
for values in (res if isinstance(res, list) else [res]):
self._get_reified_groups(group_fields, values)
+ if inject_groups_id:
+ values.pop('groups_id', None)
return res
def _get_reified_groups(self, fields, values):
def fields_get(self, cr, uid, allfields=None, context=None, write_access=True):
res = super(users_view, self).fields_get(cr, uid, allfields, context, write_access)
# add reified groups fields
- for app, kind, gs in self.pool.get('res.groups').get_groups_by_application(cr, uid, context):
+ for app, kind, gs in self.pool['res.groups'].get_groups_by_application(cr, uid, context):
if kind == 'selection':
# selection group field
tips = ['%s: %s' % (g.name, g.comment) for g in gs if g.comment]
}
return res
+#----------------------------------------------------------
+# change password wizard
+#----------------------------------------------------------
+
+class change_password_wizard(osv.TransientModel):
+ """
+ A wizard to manage the change of users' passwords
+ """
+
+ _name = "change.password.wizard"
+ _description = "Change Password Wizard"
+ _columns = {
+ 'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'),
+ }
+
+ def default_get(self, cr, uid, fields, context=None):
+ if context == None:
+ context = {}
+ user_ids = context.get('active_ids', [])
+ wiz_id = context.get('active_id', None)
+ res = []
+ users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context)
+ for user in users:
+ res.append((0, 0, {
+ 'wizard_id': wiz_id,
+ 'user_id': user.id,
+ 'user_login': user.login,
+ }))
+ return {'user_ids': res}
+
+ def change_password_button(self, cr, uid, id, context=None):
+ wizard = self.browse(cr, uid, id, context=context)[0]
+ need_reload = any(uid == user.user_id.id for user in wizard.user_ids)
+ line_ids = [user.id for user in wizard.user_ids]
+
+ self.pool.get('change.password.user').change_password_button(cr, uid, line_ids, context=context)
+ # don't keep temporary password copies in the database longer than necessary
+ self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context)
+
+ if need_reload:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'reload'
+ }
+
+ return {'type': 'ir.actions.act_window_close'}
+
+class change_password_user(osv.TransientModel):
+ """
+ A model to configure users in the change password wizard
+ """
+
+ _name = 'change.password.user'
+ _description = 'Change Password Wizard User'
+ _columns = {
+ 'wizard_id': fields.many2one('change.password.wizard', string='Wizard', required=True),
+ 'user_id': fields.many2one('res.users', string='User', required=True),
+ 'user_login': fields.char('User Login', readonly=True),
+ 'new_passwd': fields.char('New Password'),
+ }
+ _defaults = {
+ 'new_passwd': '',
+ }
+
+ def change_password_button(self, cr, uid, ids, context=None):
+ for user in self.browse(cr, uid, ids, context=context):
+ self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd})
+
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1. Try a few common expressions to verify they work with safe_eval
-
!python {model: ir.model}: |
- from tools.safe_eval import safe_eval
+ from openerp.tools.safe_eval import safe_eval
expected = (1, {"a": 9 * 2}, (True, False, None))
actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
assert actual == expected, "Simple python expressions are not working with safe_eval"
5. Try forbidden expressions in safe_eval to verify they are not allowed (open)
-
!python {model: ir.model}: |
- from tools.safe_eval import safe_eval
- from tools.misc import mute_logger
+ from openerp.tools.safe_eval import safe_eval
+ from openerp.tools.misc import mute_logger
try:
with mute_logger('openerp.tools.safe_eval'):
safe_eval('open("/etc/passwd","r")')
assert False, "safe_eval should not allow calling open() builtin"
- except NameError:
+ except ValueError:
pass
-
"Float precision tests: verify that float rounding methods are working correctly via res.currency"
-
!python {model: res.currency}: |
- from tools import float_repr
+ from openerp.tools import float_repr
from math import log10
currency = self.browse(cr, uid, ref('base.EUR'))
def try_round(amount, expected, self=self, cr=cr, currency=currency, float_repr=float_repr,
"Float precision tests: verify that float rounding methods are working correctly via tools"
-
!python {model: res.currency}: |
- from tools import float_compare, float_is_zero, float_round, float_repr
+ from openerp.tools import float_compare, float_is_zero, float_round, float_repr
def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr):
result = float_repr(float_round(amount, precision_digits=precision_digits),
precision_digits=precision_digits)
!python {model: res.currency}: |
currency = self.browse(cr, uid, ref('base.EUR'))
res_currency_rate = self.pool.get('res.currency.rate')
- from tools import float_compare, float_is_zero, float_round, float_repr
+ from openerp.tools import float_compare, float_is_zero, float_round, float_repr
def try_roundtrip(value, expected, self=self, cr=cr, currency=currency,
res_currency_rate=res_currency_rate):
rate_id = res_currency_rate.create(cr, 1, {'name':'2000-01-01',
"Float precision tests: verify that invalid parameters are forbidden"
-
!python {model: res.currency}: |
- from tools import float_compare, float_is_zero, float_round
+ from openerp.tools import float_compare, float_is_zero, float_round
try:
float_is_zero(0.01, precision_digits=3, precision_rounding=0.01)
except AssertionError:
float_round(0.01, precision_digits=3, precision_rounding=0.01)
except AssertionError:
pass
+ -
+ Test res.groups name search
+ -
+ !python {model: res.groups}: |
+ all_groups = self.search(cr, uid, [])
+ full_names = [(group.id, group.full_name) for group in self.browse(cr, uid, all_groups)]
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Sale%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sale' in full_name]), "did not match search for 'Sale'"
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Technical%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Technical' in full_name]), "did not match search for 'Technical'"
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Sales /%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sales /' in full_name]), "did not match search for 'Sales /'"
+ group_ids = self.search(cr, uid, [('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
+ assert group_ids, "did not match search for 'Administration / Access Rights' and 'Contact Creation'"
import os.path
import pickle
import re
+import sys
# for eval context:
import time
-import openerp.release as release
+
+import openerp
+import openerp.release
+import openerp.workflow
+from yaml_import import convert_yaml_import
import assertion_report
from datetime import datetime, timedelta
-from lxml import etree
+from dateutil.relativedelta import relativedelta
+from lxml import etree, builder
import misc
-import openerp.pooler as pooler
from config import config
from translate import _
unsafe_eval = eval
from safe_eval import safe_eval as eval
-class ConvertError(Exception):
- def __init__(self, doc, orig_excpt):
- self.d = doc
- self.orig = orig_excpt
+class ParseError(Exception):
+ def __init__(self, msg, text, filename, lineno):
+ self.msg = msg
+ self.text = text
+ self.filename = filename
+ self.lineno = lineno
def __str__(self):
- return 'Exception:\n\t%s\nUsing file:\n%s' % (self.orig, self.d)
+ return '"%s" while parsing %s:%s, near\n%s' \
+ % (self.msg, self.filename, self.lineno, self.text)
def _ref(self, cr):
return lambda x: self.id_get(cr, x)
def _obj(pool, cr, uid, model_str, context=None):
- model = pool.get(model_str)
+ model = pool[model_str]
return lambda x: model.browse(cr, uid, x, context=context)
def _get_idref(self, cr, uid, model_str, context, idref):
idref2 = dict(idref,
time=time,
DateTime=datetime,
+ datetime=datetime,
timedelta=timedelta,
- version=release.major_version,
+ relativedelta=relativedelta,
+ version=openerp.release.major_version,
ref=_ref(self, cr),
pytz=pytz)
if len(model_str):
if f_search:
idref2 = _get_idref(self, cr, uid, f_model, context, idref)
q = unsafe_eval(f_search, idref2)
- ids = pool.get(f_model).search(cr, uid, q)
+ ids = pool[f_model].search(cr, uid, q)
if f_use != 'id':
- ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
- _cols = pool.get(f_model)._columns
+ ids = map(lambda x: x[f_use], pool[f_model].read(cr, uid, ids, [f_use]))
+ _cols = pool[f_model]._columns
if (f_name in _cols) and _cols[f_name]._type=='many2many':
return ids
f_val = False
'Could not eval(%s) for %s in %s', a_eval, node.get('name'), context)
raise
def _process(s, idref):
- m = re.findall('[^%]%\((.*?)\)[ds]', s)
- for id in m:
+ matches = re.finditer('[^%]%\((.*?)\)[ds]', s)
+ done = []
+ for m in matches:
+ found = m.group()[1:]
+ if found in done:
+ continue
+ done.append(found)
+ id = m.groups()[0]
if not id in idref:
- idref[id]=self.id_get(cr, id)
- return s % idref
+ idref[id] = self.id_get(cr, id)
+ s = s.replace(found, str(idref[id]))
+
+ s = s.replace('%%', '%') # Quite wierd but it's for (somewhat) backward compatibility sake
+
+ return s
+
if t == 'xml':
_fix_multiple_roots(node)
return '<?xml version="1.0"?>\n'\
if t == 'html':
return _process("".join([etree.tostring(n, encoding='utf-8')
for n in node]), idref)
- if t in ('char', 'int', 'float'):
- d = node.text
- if t == 'int':
- d = d.strip()
- if d == 'None':
- return None
- else:
- return int(d.strip())
- elif t == 'float':
- return float(d.strip())
- return d
- elif t in ('list','tuple'):
+
+ data = node.text
+ if node.get('file'):
+ with openerp.tools.file_open(node.get('file'), 'rb') as f:
+ data = f.read()
+
+ if t == 'file':
+ from ..modules import module
+ path = data.strip()
+ if not module.get_module_resource(self.module, path):
+ raise IOError("No such file or directory: '%s' in %s" % (
+ path, self.module))
+ return '%s,%s' % (self.module, path)
+
+ if t == 'char':
+ return data
+
+ if t == 'base64':
+ return data.encode('base64')
+
+ if t == 'int':
+ d = data.strip()
+ if d == 'None':
+ return None
+ return int(d)
+
+ if t == 'float':
+ return float(data.strip())
+
+ if t in ('list','tuple'):
res=[]
- for n in node.findall('./value'):
+ for n in node.iterchildren(tag='value'):
res.append(_eval_xml(self,n,pool,cr,uid,idref))
if t=='tuple':
return tuple(res)
return_val = _eval_xml(self,n, pool, cr, uid, idref, context)
if return_val is not None:
args.append(return_val)
- model = pool.get(node.get('model',''))
+ model = pool[node.get('model','')]
method = node.get('name','')
res = getattr(model, method)(cr, uid, *args)
return res
maximum one dot. They are used to refer to other modules ID, in the
form: module.record_id""" % (xml_id,)
if module != self.module:
- modcnt = self.pool.get('ir.module.module').search_count(self.cr, self.uid, ['&', ('name', '=', module), ('state', 'in', ['installed'])])
+ modcnt = self.pool['ir.module.module'].search_count(self.cr, self.uid, ['&', ('name', '=', module), ('state', 'in', ['installed'])])
assert modcnt == 1, """The ID "%s" refers to an uninstalled module""" % (xml_id,)
if len(id) > 64:
if d_search:
idref = _get_idref(self, cr, self.uid, d_model, context={}, idref={})
- ids = self.pool.get(d_model).search(cr, self.uid, unsafe_eval(d_search, idref))
+ ids = self.pool[d_model].search(cr, self.uid, unsafe_eval(d_search, idref))
if d_id:
try:
ids.append(self.id_get(cr, d_id))
# d_id cannot be found. doesn't matter in this case
pass
if ids:
- self.pool.get(d_model).unlink(cr, self.uid, ids)
+ self.pool[d_model].unlink(cr, self.uid, ids)
def _remove_ir_values(self, cr, name, value, model):
- ir_values_obj = self.pool.get('ir.values')
+ ir_values_obj = self.pool['ir.values']
ir_value_ids = ir_values_obj.search(cr, self.uid, [('name','=',name),('value','=',value),('model','=',model)])
if ir_value_ids:
ir_values_obj.unlink(cr, self.uid, ir_value_ids)
res[dest] = rec.get(f,'').encode('utf8')
assert res[dest], "Attribute %s of report is empty !" % (f,)
for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'),
- ('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage')):
+ ('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage'),
+ ('report_type', 'report_type'), ('parser', 'parser')):
if rec.get(field):
res[dest] = rec.get(field).encode('utf8')
if rec.get('auto'):
res['report_sxw_content'] = sxw_content
if 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','False'))
groups_value.append((4, group_id))
res['groups_id'] = groups_value
- 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)
+ id = self.pool['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','False')):
keyword = str(rec.get('keyword', 'client_print_multi'))
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)
+ self.pool['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)
groups_value.append((4, group_id))
res['groups_id'] = groups_value
- 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)
+ id = self.pool['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','False'))) and id:
keyword = str(rec.get('keyword','') or 'client_action_multi')
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)
+ self.pool['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)
res = {'name': name, 'url': url, 'target':target}
- id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.act_url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
+ id = self.pool['ir.model.data']._update(cr, self.uid, "ir.actions.act_url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
def _tag_act_window(self, cr, rec, data_node=None):
if rec.get('target'):
res['target'] = rec.get('target','')
if rec.get('multi'):
- res['multi'] = rec.get('multi', False)
- id = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
+ res['multi'] = eval(rec.get('multi', 'False'))
+ id = self.pool['ir.model.data']._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if src_model:
keyword = rec.get('key2','').encode('utf-8') or 'client_action_relate'
value = 'ir.actions.act_window,'+str(id)
replace = rec.get('replace','') or True
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
+ self.pool['ir.model.data'].ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
# TODO add remove ir.model.data
def _tag_ir_set(self, cr, rec, data_node=None):
f_name = field.get("name",'').encode('utf-8')
f_val = _eval_xml(self,field,self.pool, cr, self.uid, self.idref)
res[f_name] = f_val
- self.pool.get('ir.model.data').ir_set(cr, self.uid, res['key'], res['key2'], res['name'], res['models'], res['value'], replace=res.get('replace',True), isobject=res.get('isobject', False), meta=res.get('meta',None))
+ self.pool['ir.model.data'].ir_set(cr, self.uid, res['key'], res['key2'], res['name'], res['models'], res['value'], replace=res.get('replace',True), isobject=res.get('isobject', False), meta=res.get('meta',None))
def _tag_workflow(self, cr, rec, data_node=None):
if self.isnoupdate(data_node) and self.mode != 'init':
id = _eval_xml(self, rec[0], self.pool, cr, self.uid, self.idref)
uid = self.get_uid(cr, self.uid, data_node, rec)
- import openerp.netsvc as netsvc
- wf_service = netsvc.LocalService("workflow")
- wf_service.trg_validate(uid, model,
+ openerp.workflow.trg_validate(uid, model,
id,
str(rec.get('action','')), cr)
else:
# the menuitem does't exist but we are in branch (not a leaf)
_logger.warning('Warning no ID for submenu %s of menu %s !', menu_elem, str(m_l))
- pid = self.pool.get('ir.ui.menu').create(cr, self.uid, {'parent_id' : pid, 'name' : menu_elem})
+ pid = self.pool['ir.ui.menu'].create(cr, self.uid, {'parent_id' : pid, 'name' : menu_elem})
values['parent_id'] = pid
else:
# The parent attribute was specified, if non-empty determine its ID, otherwise
"Verify that this is a window action or add a type argument." % (a_action,)
action_type,action_mode,action_name,view_id,target = rrres
if view_id:
- cr.execute('SELECT arch FROM ir_ui_view WHERE id=%s', (int(view_id),))
- arch, = cr.fetchone()
- action_mode = etree.fromstring(arch.encode('utf8')).tag
+ view_arch = self.pool['ir.ui.view'].read(cr, 1, [view_id], ['arch'])
+ action_mode = etree.fromstring(view_arch[0]['arch'].encode('utf8')).tag
cr.execute('SELECT view_mode FROM ir_act_window_view WHERE act_window_id=%s ORDER BY sequence LIMIT 1', (int(a_id),))
if cr.rowcount:
action_mode, = cr.fetchone()
groups_value.append((4, group_id))
values['groups_id'] = groups_value
- pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, rec_id, noupdate=self.isnoupdate(data_node), mode=self.mode, res_id=res and res[0] or False)
+ pid = self.pool['ir.model.data']._update(cr, self.uid, 'ir.ui.menu', self.module, values, rec_id, noupdate=self.isnoupdate(data_node), mode=self.mode, res_id=res and res[0] or False)
if rec_id and pid:
self.idref[rec_id] = int(pid)
if rec.get('action') and pid:
action = "ir.actions.%s,%d" % (a_type, a_id)
- self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
+ self.pool['ir.model.data'].ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
return 'ir.ui.menu', pid
def _assert_equals(self, f1, f2, prec=4):
return
rec_model = rec.get("model",'').encode('ascii')
- model = self.pool.get(rec_model)
- assert model, "The model %s does not exist !" % (rec_model,)
+ model = self.pool[rec_model]
rec_id = rec.get("id",'').encode('ascii')
self._test_xml_id(rec_id)
rec_src = rec.get("search",'').encode('utf8')
ids = [self.id_get(cr, rec_id)]
elif rec_src:
q = unsafe_eval(rec_src, eval_dict)
- ids = self.pool.get(rec_model).search(cr, uid, q, context=context)
+ ids = self.pool[rec_model].search(cr, uid, q, context=context)
if rec_src_count:
count = int(rec_src_count)
if len(ids) != count:
def _tag_record(self, cr, rec, data_node=None):
rec_model = rec.get("model").encode('ascii')
- model = self.pool.get(rec_model)
- assert model, "The model %s does not exist !" % (rec_model,)
+ model = self.pool[rec_model]
rec_id = rec.get("id",'').encode('ascii')
rec_context = rec.get("context", None)
if rec_context:
rec_context = unsafe_eval(rec_context)
self._test_xml_id(rec_id)
+ # in update mode, the record won't be updated if the data node explicitely
+ # opt-out using @noupdate="1". A second check will be performed in
+ # ir.model.data#_update() using the record's ir.model.data `noupdate` field.
if self.isnoupdate(data_node) and self.mode != 'init':
# check if the xml record has an id string
if rec_id:
else:
module = self.module
rec_id2 = rec_id
- id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, module, rec_id2)
+ id = self.pool['ir.model.data']._update_dummy(cr, self.uid, rec_model, module, rec_id2)
# check if the resource already existed at the last update
if id:
# if it existed, we don't update the data, but we need to
f_ref = field.get("ref",'').encode('utf-8')
f_search = field.get("search",'').encode('utf-8')
f_model = field.get("model",'').encode('utf-8')
- if not f_model and model._columns.get(f_name,False):
- f_model = model._columns[f_name]._obj
+ if not f_model and model._all_columns.get(f_name,False):
+ f_model = model._all_columns[f_name].column._obj
f_use = field.get("use",'').encode('utf-8') or 'id'
f_val = False
q = unsafe_eval(f_search, self.idref)
field = []
assert f_model, 'Define an attribute model="..." in your .XML file !'
- f_obj = self.pool.get(f_model)
+ f_obj = self.pool[f_model]
# browse the objects searched
s = f_obj.browse(cr, self.uid, f_obj.search(cr, self.uid, q))
# column definitions of the "local" object
- _cols = self.pool[rec_model]._columns
- _cols = self.pool.get(rec_model)._all_columns
++ _cols = self.pool[rec_model]._all_columns
# if the current field is many2many
- if (f_name in _cols) and _cols[f_name]._type=='many2many':
+ if (f_name in _cols) and _cols[f_name].column._type=='many2many':
f_val = [(6, 0, map(lambda x: x[f_use], s))]
elif len(s):
# otherwise (we are probably in a many2one field),
if f_ref=="null":
f_val = False
else:
- if f_name in model._columns \
- and model._columns[f_name]._type == 'reference':
+ if f_name in model._all_columns \
+ and model._all_columns[f_name].column._type == 'reference':
val = self.model_id_get(cr, f_ref)
f_val = val[0] + ',' + str(val[1])
else:
f_val = self.id_get(cr, f_ref)
else:
f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
- if model._columns.has_key(f_name):
+ if f_name in model._all_columns:
import openerp.osv as osv
- if isinstance(model._columns[f_name], osv.fields.integer):
+ if isinstance(model._all_columns[f_name].column, osv.fields.integer):
f_val = int(f_val)
res[f_name] = f_val
- id = self.pool.get('ir.model.data')._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not self.isnoupdate(data_node), noupdate=self.isnoupdate(data_node), mode=self.mode, context=rec_context )
+ id = self.pool['ir.model.data']._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not self.isnoupdate(data_node), noupdate=self.isnoupdate(data_node), mode=self.mode, context=rec_context )
if rec_id:
self.idref[rec_id] = int(id)
if config.get('import_partial', False):
cr.commit()
return rec_model, id
+ def _tag_template(self, cr, el, data_node=None):
+ # This helper transforms a <template> element into a <record> and forwards it
+ tpl_id = el.get('id', el.get('t-name', '')).encode('ascii')
+ module = self.module
+ if '.' in tpl_id:
+ module, tpl_id = tpl_id.split('.', 1)
+ # set the full template name for qweb <module>.<id>
+ if not (el.get('inherit_id') or el.get('inherit_option_id')):
+ el.set('t-name', '%s.%s' % (module, tpl_id))
+ el.tag = 't'
+ else:
+ el.tag = 'data'
+ el.attrib.pop('id', None)
+
+ record_attrs = {
+ 'id': tpl_id,
+ 'model': 'ir.ui.view',
+ }
+ for att in ['forcecreate', 'context']:
+ if att in el.keys():
+ record_attrs[att] = el.attrib.pop(att)
+
+ Field = builder.E.field
+ name = el.get('name', tpl_id)
+
+ record = etree.Element('record', attrib=record_attrs)
+ record.append(Field(name, name='name'))
+ record.append(Field("qweb", name='type'))
+ record.append(Field(el.get('priority', "16"), name='priority'))
+ record.append(Field(el, name="arch", type="xml"))
+ for field_name in ('inherit_id','inherit_option_id'):
+ value = el.attrib.pop(field_name, None)
+ if value: record.append(Field(name=field_name, ref=value))
+ groups = el.attrib.pop('groups', None)
+ if groups:
+ grp_lst = map(lambda x: "ref('%s')" % x, groups.split(','))
+ record.append(Field(name="groups_id", eval="[(6, 0, ["+', '.join(grp_lst)+"])]"))
+ if el.attrib.pop('page', None) == 'True':
+ record.append(Field(name="page", eval="True"))
+
+ return self._tag_record(cr, record, data_node)
+
def id_get(self, cr, id_str):
if id_str in self.idref:
return self.idref[id_str]
return res
def model_id_get(self, cr, id_str):
- model_data_obj = self.pool.get('ir.model.data')
+ model_data_obj = self.pool['ir.model.data']
mod = self.module
if '.' in id_str:
mod,id_str = id_str.split('.')
return model_data_obj.get_object_reference(cr, self.uid, mod, id_str)
def parse(self, de):
- if not de.tag in ['terp', 'openerp']:
- _logger.error("Mismatch xml format")
- raise Exception( "Mismatch xml format: only terp or openerp as root tag" )
-
- if de.tag == 'terp':
- _logger.warning("The tag <terp/> is deprecated, use <openerp/>")
+ if de.tag != 'openerp':
+ raise Exception("Mismatch xml format: root tag must be `openerp`.")
for n in de.findall('./data'):
for rec in n:
if rec.tag in self._tags:
try:
self._tags[rec.tag](self.cr, rec, n)
- except:
- _logger.error('Parse error in %s:%d: \n%s',
- rec.getroottree().docinfo.URL,
- rec.sourceline,
- etree.tostring(rec).strip(), exc_info=True)
+ except Exception, e:
self.cr.rollback()
- raise
+ exc_info = sys.exc_info()
+ raise ParseError, (misc.ustr(e), etree.tostring(rec).rstrip(), rec.getroottree().docinfo.URL, rec.sourceline), exc_info[2]
return True
def __init__(self, cr, module, idref, mode, report=None, noupdate=False):
self.module = module
self.cr = cr
self.idref = idref
- self.pool = pooler.get_pool(cr.dbname)
+ self.pool = openerp.registry(cr.dbname)
self.uid = 1
if report is None:
report = assertion_report.assertion_report()
self._tags = {
'menuitem': self._tag_menuitem,
'record': self._tag_record,
+ 'template': self._tag_template,
'assert': self._tag_assert,
'report': self._tag_report,
'wizard': self._tag_wizard,
'url': self._tag_url
}
+def convert_file(cr, module, filename, idref, mode='update', noupdate=False, kind=None, report=None):
+ pathname = os.path.join(module, filename)
+ fp = misc.file_open(pathname)
+ ext = os.path.splitext(filename)[1].lower()
+ try:
+ if ext == '.csv':
+ convert_csv_import(cr, module, pathname, fp.read(), idref, mode, noupdate)
+ elif ext == '.sql':
+ convert_sql_import(cr, fp)
+ elif ext == '.yml':
+ convert_yaml_import(cr, module, fp, kind, idref, mode, noupdate, report)
+ elif ext == '.xml':
+ convert_xml_import(cr, module, fp, idref, mode, noupdate, report)
+ elif ext == '.js':
+ pass # .js files are valid but ignored here.
+ else:
+ _logger.warning("Can't load unknown file type %s.", filename)
+ finally:
+ fp.close()
+
+def convert_sql_import(cr, fp):
+ queries = fp.read().split(';')
+ for query in queries:
+ new_query = ' '.join(query.split())
+ if new_query:
+ cr.execute(new_query)
+
def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
noupdate=False):
'''Import csv file :
#remove folder path from model
head, model = os.path.split(model)
- pool = pooler.get_pool(cr.dbname)
-
input = cStringIO.StringIO(csvcontent) #FIXME
reader = csv.reader(input, quotechar='"', delimiter=',')
fields = reader.next()
uid = 1
datas = []
for line in reader:
- if (not line) or not reduce(lambda x,y: x or y, line) :
+ if not (line and any(line)):
continue
try:
- datas.append(map(lambda x: misc.ustr(x), line))
+ datas.append(map(misc.ustr, line))
except:
_logger.error("Cannot import the line: %s", line)
- result, rows, warning_msg, dummy = pool.get(model).import_data(cr, uid, fields, datas,mode, module, noupdate, filename=fname_partial)
+
+ registry = openerp.registry(cr.dbname)
+ result, rows, warning_msg, dummy = registry[model].import_data(cr, uid, fields, datas,mode, module, noupdate, filename=fname_partial)
if result < 0:
# Report failed import and abort module install
raise Exception(_('Module loading %s failed: file %s could not be processed:\n %s') % (module, fname, warning_msg))