[merge] lp:openobject-server/7.0

bzr revid: jam@tinyerp.com-20130611051458-r4bg46apl7j6kfrf
This commit is contained in:
Jigar Amin (OpenERP) 2013-06-11 10:44:58 +05:30
commit d334814bf5
110 changed files with 44088 additions and 32478 deletions

8
debian/copyright vendored
View File

@ -40,7 +40,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
@ -93,7 +93,7 @@ License: LGPL-2.1
.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU Library General Public License
can be found in /usr/share/common-licenses/LGPL-2.1 file.
@ -137,7 +137,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
@ -159,7 +159,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#

View File

@ -24,7 +24,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################

View File

@ -1,4 +1,3 @@
#!/usr/bin/python
# WSGI Handler sample configuration file.
#
# Change the appropriate settings below, in order to provide the parameters

View File

@ -49,8 +49,6 @@
<field name="symbol"></field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<!-- Company ID will be set later -->
<field name="company_id" eval="None"/>
</record>
<record id="rateEUR" model="res.currency.rate">
<field name="rate">1.0</field>
@ -86,10 +84,6 @@ Administrator</field>
<field name="company_id" ref="main_company"/>
</record>
<record id="EUR" model="res.currency">
<field name="company_id" ref="main_company"/>
</record>
<record id="ir_mail_server_localhost0" model="ir.mail_server">
<field name="name">localhost</field>
<field name="smtp_host">localhost</field>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -603,7 +603,7 @@ class actions_server(osv.osv):
if action.state=='client_action':
if not action.action_id:
raise osv.except_osv(_('Error'), _("Please specify an action to launch !"))
raise osv.except_osv(_('Error'), _("Please specify an action to launch!"))
return self.pool.get(action.action_id.type)\
.read(cr, uid, action.action_id.id, context=context)

View File

@ -198,7 +198,7 @@ class ir_attachment(osv.osv):
continue
res_ids.setdefault(rmod,set()).add(rid)
if values:
if 'res_model' in values and 'res_id' in values:
if values.get('res_model') and 'res_id' in values:
res_ids.setdefault(values['res_model'],set()).add(values['res_id'])
ima = self.pool.get('ir.model.access')

View File

@ -31,6 +31,7 @@ import re
import smtplib
import threading
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools import html2text
@ -211,14 +212,14 @@ class ir_mail_server(osv.osv):
password=smtp_server.smtp_pass, encryption=smtp_server.smtp_encryption,
smtp_debug=smtp_server.smtp_debug)
except Exception, e:
raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e))
raise osv.except_osv(_("Connection Test Failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e))
finally:
try:
if smtp: smtp.quit()
except Exception:
# ignored, just a consequence of the previous exception
pass
raise osv.except_osv(_("Connection test succeeded!"), _("Everything seems properly set up!"))
raise osv.except_osv(_("Connection Test Succeeded!"), _("Everything seems properly set up!"))
def connect(self, host, port, user=None, password=None, encryption=False, smtp_debug=False):
"""Returns a new SMTP connection to the give SMTP server, authenticated
@ -417,11 +418,11 @@ class ir_mail_server(osv.osv):
# Get SMTP Server Details from Mail Server
mail_server = None
if mail_server_id:
mail_server = self.browse(cr, uid, mail_server_id)
mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id)
elif not smtp_server:
mail_server_ids = self.search(cr, uid, [], order='sequence', limit=1)
mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1)
if mail_server_ids:
mail_server = self.browse(cr, uid, mail_server_ids[0])
mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0])
if mail_server:
smtp_server = mail_server.smtp_host

View File

@ -82,7 +82,7 @@ class ir_model(osv.osv):
return []
__, operator, value = domain[0]
if operator not in ['=', '!=']:
raise osv.except_osv(_('Invalid search criterions'), _('The osv_memory field can only be compared with = and != operator.'))
raise osv.except_osv(_("Invalid Search Criteria"), _('The osv_memory field can only be compared with = and != operator.'))
value = bool(value) if operator == '=' else not bool(value)
all_model_ids = self.search(cr, uid, [], context=context)
is_osv_mem = self._is_osv_memory(cr, uid, all_model_ids, 'osv_memory', arg=None, context=context)

View File

@ -54,6 +54,34 @@ class ir_sequence(openerp.osv.osv.osv):
"""
_name = 'ir.sequence'
_order = 'name'
def _get_number_next_actual(self, cr, user, ids, field_name, arg, context=None):
'''Return number from ir_sequence row when no_gap implementation,
and number from postgres sequence when standard implementation.'''
res = dict.fromkeys(ids)
for element in self.browse(cr, user, ids, context=context):
if element.implementation != 'standard':
res[element.id] = element.number_next
else:
# get number from postgres sequence. Cannot use
# currval, because that might give an error when
# not having used nextval before.
statement = (
"SELECT last_value, increment_by, is_called"
" FROM ir_sequence_%03d"
% element.id)
cr.execute(statement)
(last_value, increment_by, is_called) = cr.fetchone()
if is_called:
res[element.id] = last_value + increment_by
else:
res[element.id] = last_value
return res
def _set_number_next_actual(self, cr, uid, id, name, value, args=None, context=None):
return self.write(cr, uid, id, {'number_next': value or 0}, context=context)
_columns = {
'name': openerp.osv.fields.char('Name', size=64, required=True),
'code': openerp.osv.fields.selection(_code_get, 'Code', size=64),
@ -67,6 +95,7 @@ class ir_sequence(openerp.osv.osv.osv):
'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"),
'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"),
'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"),
'number_next_actual': openerp.osv.fields.function(_get_number_next_actual, fnct_inv=_set_number_next_actual, type='integer', required=True, string='Next Number', help='Next number that will be used. This number can be incremented frequently so the displayed value might already be obsolete'),
'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"),
'padding' : openerp.osv.fields.integer('Number Padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."),
'company_id': openerp.osv.fields.many2one('res.company', 'Company'),
@ -77,6 +106,7 @@ class ir_sequence(openerp.osv.osv.osv):
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.sequence', context=c),
'number_increment': 1,
'number_next': 1,
'number_next_actual': 1,
'padding' : 0,
}
@ -121,7 +151,7 @@ class ir_sequence(openerp.osv.osv.osv):
# object depends on it.
cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names)
def _alter_sequence(self, cr, id, number_increment, number_next):
def _alter_sequence(self, cr, id, number_increment, number_next=None):
""" Alter a PostreSQL sequence.
There is no access rights check.
@ -129,9 +159,15 @@ class ir_sequence(openerp.osv.osv.osv):
if number_increment == 0:
raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))
assert isinstance(id, (int, long))
cr.execute("""
ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s
""" % id, (number_increment, number_next))
seq_name = 'ir_sequence_%03d' % (id,)
cr.execute("SELECT relname FROM pg_class WHERE relkind = %s AND relname=%s", ('S', seq_name))
if not cr.fetchone():
# sequence is not created yet, we're inside create() so ignore it, will be set later
return
statement = "ALTER SEQUENCE %s INCREMENT BY %d" % (seq_name, number_increment)
if number_next is not None:
statement += " RESTART WITH %d" % (number_next, )
cr.execute(statement)
def create(self, cr, uid, values, context=None):
""" Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.
@ -160,7 +196,13 @@ class ir_sequence(openerp.osv.osv.osv):
n = values.get('number_next', row['number_next'])
if row['implementation'] == 'standard':
if new_implementation in ('standard', None):
self._alter_sequence(cr, row['id'], i, n)
# Implementation has NOT changed.
# Only change sequence if really requested.
if row['number_next'] != n:
self._alter_sequence(cr, row['id'], i, n)
else:
# Just in case only increment changed
self._alter_sequence(cr, row['id'], i)
else:
self._drop_sequence(cr, row['id'])
else:
@ -200,7 +242,7 @@ class ir_sequence(openerp.osv.osv.osv):
force_company = context.get('force_company')
if not force_company:
force_company = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
sequences = self.read(cr, uid, seq_ids, ['company_id','implementation','number_next','prefix','suffix','padding'])
sequences = self.read(cr, uid, seq_ids, ['name','company_id','implementation','number_next','prefix','suffix','padding'])
preferred_sequences = [s for s in sequences if s['company_id'] and s['company_id'][0] == force_company ]
seq = preferred_sequences[0] if preferred_sequences else sequences[0]
if seq['implementation'] == 'standard':
@ -210,8 +252,11 @@ class ir_sequence(openerp.osv.osv.osv):
cr.execute("SELECT number_next FROM ir_sequence WHERE id=%s FOR UPDATE NOWAIT", (seq['id'],))
cr.execute("UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s ", (seq['id'],))
d = self._interpolation_dict()
interpolated_prefix = self._interpolate(seq['prefix'], d)
interpolated_suffix = self._interpolate(seq['suffix'], d)
try:
interpolated_prefix = self._interpolate(seq['prefix'], d)
interpolated_suffix = self._interpolate(seq['suffix'], d)
except ValueError:
raise osv.except_osv(_('Warning'), _('Invalid prefix or suffix for sequence \'%s\'') % (seq.get('name')))
return interpolated_prefix + '%%0%sd' % seq['padding'] % seq['number_next'] + interpolated_suffix
def next_by_id(self, cr, uid, sequence_id, context=None):

View File

@ -20,7 +20,7 @@
<field name="suffix"/>
<field name="padding"/>
<field name="number_increment"/>
<field name="number_next"/>
<field name="number_next_actual"/>
<field name="implementation"/>
</group>
<group col="3" string="Legend (for prefix, suffix)">
@ -57,7 +57,7 @@
<field name="prefix"/>
<field name="padding"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="number_next"/>
<field name="number_next_actual"/>
<field name="number_increment"/>
<field name="implementation"/>
</tree>

View File

@ -411,8 +411,8 @@ class ir_values(osv.osv):
(tuple(groups), uid))
if not cr.fetchone():
if action['name'] == 'Menuitem':
raise osv.except_osv('Error !',
'You do not have the permission to perform this operation !!!')
raise osv.except_osv('Error!',
'You do not have the permission to perform this operation!!!')
continue
# keep only the first action registered for each action name
results[action['name']] = (action['id'], action['name'], action_def)

View File

@ -96,7 +96,7 @@ class wkf_activity(osv.osv):
def unlink(self, cr, uid, ids, context=None):
if context is None: context = {}
if not context.get('_force_unlink') and self.pool.get('workflow.workitem').search(cr, uid, [('act_id', 'in', ids)]):
raise osv.except_osv(_('Operation forbidden'),
raise osv.except_osv(_('Operation Forbidden'),
_('Please make sure no workitems refer to an activity before deleting it!'))
super(wkf_activity, self).unlink(cr, uid, ids, context=context)

View File

@ -55,7 +55,7 @@ class base_module_import(osv.osv_memory):
try:
file_data = zipfile.ZipFile(fp, 'r')
except zipfile.BadZipfile:
raise osv.except_osv(_('Error !'), _('File is not a zip file!'))
raise osv.except_osv(_('Error!'), _('File is not a zip file!'))
init_file_name = sorted(file_data.namelist())[0]
module_name = os.path.split(init_file_name)[0]
@ -63,8 +63,8 @@ class base_module_import(osv.osv_memory):
try:
zip_file = open(file_path, 'wb')
except IOError:
raise osv.except_osv(_('Error !'),
_('Can not create the module file: %s !') % \
raise osv.except_osv(_('Error!'),
_('Can not create the module file: %s!') % \
(file_path,) )
zip_file.write(zip_data)
zip_file.close()

View File

@ -81,7 +81,7 @@ class base_module_upgrade(osv.osv_memory):
(tuple(ids), ('uninstalled',)))
unmet_packages = [x[0] for x in cr.fetchall()]
if unmet_packages:
raise osv.except_osv(_('Unmet dependency !'),
raise osv.except_osv(_('Unmet Dependency!'),
_('Following modules are not installed or unknown: %s') % ('\n\n' + '\n'.join(unmet_packages)))
ir_module.download(cr, uid, ids, context=context)

View File

@ -53,7 +53,13 @@
<field name="res_model">res.bank</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help">Manage bank records you want to be used in the system.</field>
<field name="help">
<p class="oe_view_nocontent_create">
Click to create a new bank.
</p><p>
Manage bank records you want to be used in the system.
</p>
</field>
</record>
<menuitem action="action_res_bank_form" id="menu_action_res_bank_form" parent="base.menu_config_address_book" sequence="11" groups="base.group_no_one"/>
@ -152,7 +158,17 @@
<field name="res_model">res.partner.bank</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help">Configure your company's bank accounts and select those that must appear on the report footer. You can reorder bank accounts from the list view. If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a bank account.
</p><p>
Configure your company's bank accounts and select those that must appear on the report footer.
You can reorder bank accounts from the list view.
</p>
<p>
If you use the accounting application of OpenERP, journals and accounts will be created automatically based on these data.
</p>
</field>
</record>
<menuitem action="action_res_partner_bank_account_form"
id="menu_action_res_partner_bank_form"

View File

@ -272,6 +272,10 @@ class res_company(osv.osv):
<header>
<pageTemplate>
<frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
<stylesheet>
<!-- Set here the default font to use for all <para> tags -->
<paraStyle name='Normal' fontName="DejaVu Sans"/>
</stylesheet>
<pageGraphics>
<fill color="black"/>
<stroke color="black"/>
@ -281,6 +285,9 @@ class res_company(osv.osv):
<drawCentredString x="%s" y="%s">[[ company.partner_id.name ]]</drawCentredString>
<stroke color="#000000"/>
<lines>%s</lines>
<!-- Set here the default font to use for all <drawString> tags -->
<!-- don't forget to change the 2 other occurence of <setFont> above if needed -->
<setFont name="DejaVu Sans" size="8"/>
</pageGraphics>
</pageTemplate>
</header>"""
@ -304,13 +311,16 @@ class res_company(osv.osv):
<pageTemplate>
<frame id="first" x1="1.3cm" y1="3.0cm" height="%s" width="19.0cm"/>
<stylesheet>
<paraStyle name="main_footer" fontName="DejaVu Sans" fontSize="8.0" alignment="CENTER"/>
<paraStyle name="main_header" fontName="DejaVu Sans" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<!-- Set here the default font to use for all <para> tags -->
<paraStyle name='Normal' fontName="DejaVu Sans"/>
<paraStyle name="main_footer" fontSize="8.0" alignment="CENTER"/>
<paraStyle name="main_header" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
</stylesheet>
<pageGraphics>
<!-- Set here the default font to use for all <drawString> tags -->
<setFont name="DejaVu Sans" size="8"/>
<!-- You Logo - Change X,Y,Width and Height -->
<image x="1.3cm" y="%s" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
<setFont name="DejaVu Sans" size="8"/>
<fill color="black"/>
<stroke color="black"/>

View File

@ -73,6 +73,7 @@ class res_currency(osv.osv):
'position' : 'after',
'rounding': 0.01,
'accuracy': 4,
'company_id': False,
}
_sql_constraints = [
# this constraint does not cover all cases due to SQL NULL handling for company_id,

View File

@ -182,11 +182,11 @@ class lang(osv.osv):
for language in languages:
ctx_lang = context.get('lang')
if language['code']=='en_US':
raise osv.except_osv(_('User Error'), _("Base Language 'en_US' can not be deleted !"))
raise osv.except_osv(_('User Error'), _("Base Language 'en_US' can not be deleted!"))
if ctx_lang and (language['code']==ctx_lang):
raise osv.except_osv(_('User Error'), _("You cannot delete the language which is User's Preferred Language !"))
raise osv.except_osv(_('User Error'), _("You cannot delete the language which is User's Preferred Language!"))
if language['active']:
raise osv.except_osv(_('User Error'), _("You cannot delete the language which is Active !\nPlease de-activate the language first."))
raise osv.except_osv(_('User Error'), _("You cannot delete the language which is Active!\nPlease de-activate the language first."))
trans_obj = self.pool.get('ir.translation')
trans_ids = trans_obj.search(cr, uid, [('lang','=',language['code'])], context=context)
trans_obj.unlink(cr, uid, trans_ids, context=context)

View File

@ -74,7 +74,8 @@ class format_address(object):
def _tz_get(self,cr,uid, context=None):
return [(x, x) for x in pytz.all_timezones]
# put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728
return [(tz,tz) for tz in sorted(pytz.all_timezones, key=lambda tz: tz if not tz.startswith('Etc/') else '_')]
class res_partner_category(osv.osv):
@ -573,7 +574,7 @@ class res_partner(osv.osv, format_address):
context = {}
name, email = self._parse_partner_name(name, context=context)
if context.get('force_email') and not email:
raise osv.except_osv(_('Warning'), _("Couldn't create contact without email address !"))
raise osv.except_osv(_('Warning'), _("Couldn't create contact without email address!"))
if not name and email:
name = email
rec_id = self.create(cr, uid, {self._rec_name: name or email, 'email': email or False}, context=context)

View File

@ -576,7 +576,14 @@
<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">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.</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new partner category.
</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.
</p>
</field>
</record>
<menuitem action="action_partner_category_form" id="menu_partner_category_form" name="Partner Tags" sequence="4" parent="menu_config_address_book" groups="base.group_no_one"/>

View File

@ -836,6 +836,7 @@ class users_view(osv.osv):
'string': app and app.name or _('Other'),
'selection': [(False, '')] + [(g.id, g.name) for g in gs],
'help': '\n'.join(tips),
'exportable': False,
}
else:
# boolean group fields
@ -844,6 +845,7 @@ class users_view(osv.osv):
'type': 'boolean',
'string': g.name,
'help': g.comment,
'exportable': False,
}
return res

View File

@ -87,6 +87,12 @@
<field name="domain_force">['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record>
<record id="res_currency_rule" model="ir.rule">
<field name="name">multi-company currency rule</field>
<field model="ir.model" name="model_id" ref="model_res_currency"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
</data>
</openerp>

View File

@ -114,7 +114,7 @@
"access_ir_filter employee","ir_filters employee","model_ir_filters","group_user",1,1,1,1
"access_ir_filters","ir_filters_all","model_ir_filters",,1,1,1,1
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
"access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
"access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
114 access_ir_filter employee ir_filters employee model_ir_filters group_user 1 1 1 1
115 access_ir_filters ir_filters_all model_ir_filters 1 1 1 1
116 access_ir_config_parameter ir_config_parameter model_ir_config_parameter 1 0 0 0
117 access_ir_mail_server_all access_ir_mail_server ir_mail_server model_ir_mail_server group_system 1 0 1 0 1 0 1
118 access_ir_actions_client ir_actions_client all model_ir_actions_client 1 0 0 0
119 access_ir_needaction_mixin ir_needaction_mixin model_ir_needaction_mixin 1 1 1 1
120

View File

@ -291,22 +291,22 @@
assert res_101 == [], 'res_101: expected %r, got %r' % ([], res_101)
assert res_102 == company_ids, 'res_102: expected %r, got %r' % (company_ids, res_102)
-
Property of the query (one2many != False).
Verify domain evaluation for `one2many != False`
-
!python {model: res.currency }: |
ids = self.search(cr, uid, [])
referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)])
companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', '!=', False)]))
assert referenced_companies == companies
!python {model: res.partner.category }: |
all_ids = self.search(cr, uid, [])
parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
result = set(self.search(cr, uid, [('child_ids', '!=', False)]))
assert result and result == parent_categs, "Got %r, expected %r" % (result, parent_categs)
-
Property of the query (one2many = False).
Verify domain evaluation for `one2many == False`
-
!python {model: res.currency }: |
ids = self.search(cr, uid, [])
referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)])
unreferenced_companies = set(self.pool.get('res.company').search(cr, uid, [])).difference(referenced_companies)
companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', '=', False)]))
assert unreferenced_companies == companies
!python {model: res.partner.category }: |
all_ids = self.search(cr, uid, [])
parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
leaf_categs = set(all_ids) - parent_categs
result = set(self.search(cr, uid, [('child_ids', '=', False)]))
assert result and result == leaf_categs, "Got %r, expected %r" % (result, leaf_categs)
-
Equivalent queries.
-
@ -375,6 +375,11 @@
currency_ids3 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [])])
assert currency_ids1 == currency_ids2 == currency_ids3, 'All 3 results should have be the same: all currencies'
default_company = self.browse(cr, uid, 1)
# Due to currency data definition change (in relation with bug 1111298), this test now needs
# a manual setup where all currencies are assigned to the default company.
self.pool['res.currency'].write(cr, uid, currency_ids1, {'company_id': default_company.id})
# one2many towards same model
res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child
res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child

View File

@ -1,3 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#

View File

@ -16,7 +16,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################

Some files were not shown because too many files have changed in this diff Show More