Thibault Delavallée (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-openchatter-3-5-user-partner-inherit-tde
 into lp:~openerp-dev/openobject-server/trunk-openchatter-3-5-tde.

Requested reviews:
  OpenERP R&D Team (openerp-dev)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-openchatter-3-5-user-partner-inherit-tde/+merge/118705

OpenChatter intra feature branch.

User inherits from partner. Server-side branch :
- res.user inherits res.partner
- context_lang -> lang on res.partner
- user_email -> email on res.partner
- context_tz -> tz on res.partner
- modified base.sql
- modified algorithm to set context from res.user: all_columns, lang and tz 
specific, now only context_*
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-openchatter-3-5-user-partner-inherit-tde/+merge/118705
Your team OpenERP R&D Team is requested to review the proposed merge of 
lp:~openerp-dev/openobject-server/trunk-openchatter-3-5-user-partner-inherit-tde
 into lp:~openerp-dev/openobject-server/trunk-openchatter-3-5-tde.
=== modified file 'openerp/addons/base/base.sql'
--- openerp/addons/base/base.sql	2012-07-17 08:50:28 +0000
+++ openerp/addons/base/base.sql	2012-08-08 10:24:40 +0000
@@ -151,9 +151,9 @@
     login varchar(64) NOT NULL UNIQUE,
     password varchar(64) default null,
     email varchar(64) default null,
-    context_tz varchar(64) default null,
+    tz varchar(64) default null,
     signature text,
-    context_lang varchar(64) default '',
+    lang varchar(64) default '',
     -- No FK references below, will be added later by ORM
     -- (when the destination rows exist)
     company_id int,
@@ -385,7 +385,7 @@
 -- Users
 ---------------------------------
 
-insert into res_users (id,login,password,name,active,company_id,context_lang) values (1,'admin','admin','Administrator',True,1,'en_US');
+insert into res_users (id,login,password,name,active,company_id,lang) values (1,'admin','admin','Administrator',True,1,'en_US');
 insert into ir_model_data (name,module,model,noupdate,res_id) values ('user_root','base','res.users',True,1);
 
 -- Compatibility purpose, to remove V6.0

=== modified file 'openerp/addons/base/base_data.xml'
--- openerp/addons/base/base_data.xml	2012-03-23 06:40:37 +0000
+++ openerp/addons/base/base_data.xml	2012-08-08 10:24:40 +0000
@@ -1087,9 +1087,15 @@
             <field name="currency_id" ref="base.EUR"/>
         </record>
 
+        <record model="res.partner" id="base.partner_root">
+            <field name="name">Administrator</field>
+            <field name="company_id" ref="main_company"/>
+        </record>
+
         <record model="res.users" id="base.user_root">
             <field name="signature">Administrator</field>
-            <field name="company_id" ref="main_company"/>
+            <field name="partner_id" ref="base.partner_root"/>
+            <!-- <field name="company_id" ref="main_company"/> -->
             <field name="menu_id" ref="action_menu_admin"/>
             <field name="company_ids" eval="[(4, ref('main_company'))]"/>
         </record>
@@ -1097,9 +1103,6 @@
         <record id="main_partner" model="res.partner">
             <field name="company_id" ref="main_company"/>
         </record>
-        <record id="EUR" model="res.currency">
-            <field name="company_id" ref="main_company"/>
-        </record>
 
         <!-- The Following currency rates are considered as on 1st Jan,2010 against EUR. -->
         <!-- Currencies -->

=== modified file 'openerp/addons/base/ir/ir_actions.py'
--- openerp/addons/base/ir/ir_actions.py	2012-08-04 21:53:00 +0000
+++ openerp/addons/base/ir/ir_actions.py	2012-08-08 10:24:40 +0000
@@ -625,8 +625,8 @@
 
                 if not email_from:
                     _logger.debug('--email-from command line option is not specified, using a fallback value instead.')
-                    if user.user_email:
-                        email_from = user.user_email
+                    if user.email:
+                        email_from = user.email
                     else:
                         email_from = "%s@%s" % (user.login, gethostname())
 

=== modified file 'openerp/addons/base/publisher_warranty/publisher_warranty.py'
--- openerp/addons/base/publisher_warranty/publisher_warranty.py	2012-05-09 05:38:31 +0000
+++ openerp/addons/base/publisher_warranty/publisher_warranty.py	2012-08-08 10:24:40 +0000
@@ -86,7 +86,7 @@
             db_create_date = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
             user = self.pool.get("res.users").browse(cr, uid, uid)
             user_name = user.name
-            email = user.user_email
+            email = user.email
 
             msg = {'contract_name': valid_contract.name,
                 'tb': tb,
@@ -333,7 +333,7 @@
         "db_create_date": db_create_date,
         "version": release.version,
         "contracts": [c.name for c in contracts],
-        "language": user.context_lang,
+        "language": user.lang,
     }
 
     add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}

=== removed file 'openerp/addons/base/res/photo.png'
Binary files openerp/addons/base/res/photo.png	2012-03-01 06:43:12 +0000 and openerp/addons/base/res/photo.png	1970-01-01 00:00:00 +0000 differ
=== modified file 'openerp/addons/base/res/res_partner.py'
--- openerp/addons/base/res/res_partner.py	2012-08-07 14:42:53 +0000
+++ openerp/addons/base/res/res_partner.py	2012-08-08 10:24:40 +0000
@@ -20,6 +20,7 @@
 ##############################################################################
 
 import math
+import openerp
 import os
 from osv import osv, fields
 import re
@@ -27,6 +28,11 @@
 from tools.translate import _
 import logging
 import pooler
+import pytz
+import random
+
+def _tz_get(self,cr,uid, context=None):
+    return [(x, x) for x in pytz.all_timezones]
 
 class res_payterm(osv.osv):
     _description = 'Payment term'
@@ -150,7 +156,12 @@
         'parent_id': fields.many2one('res.partner', 'Owned by'),
         'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'),
         'ref': fields.char('Reference', size=64, select=1),
-        'lang': fields.selection(_lang_get, 'Language', help="If the selected language is loaded in the system, all documents related to this partner will be printed in this language. If not, it will be english."),
+        'lang': fields.selection(_lang_get, 'Language',
+            help="If the selected language is loaded in the system, all documents related to this partner will be printed in this language. If not, it will be english."),
+        'tz': fields.selection(_tz_get,  'Timezone', size=64,
+            help="The partner's timezone, used to output proper date and time values inside printed reports. "
+                 "It is important to set a value for this field. You should use the same timezone "
+                 "that is otherwise used to pick and render date and time values: your computer's timezone."),
         'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this partner if any.'),
         'vat': fields.char('VAT',size=32 ,help="Value Added Tax number. Check the box if the partner is subjected to the VAT. Used by the VAT legal statement."),
         'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),
@@ -203,7 +214,11 @@
             help="Small-sized image of the partner. It is automatically "\
                  "resized as a 50x50 px image, with aspect ratio preserved. "\
                  "Use this field anywhere a small image is required."),
-        'company_id': fields.many2one('res.company', 'Company', select=1),
+        # Special behavior for this field: res.company.search() will only return the companies
+        # available to the current user (should be the user's companies?), when the user_preference
+        # context is set.
+        'company_id': fields.many2one('res.company', 'Company', select=1,
+            help="The company this partner is currently working for.", context={'user_preference': True}),
         'color': fields.integer('Color Index'),
         'contact_address': fields.function(_address_display,  type='char', string='Complete Address'),
     }
@@ -217,13 +232,15 @@
 
     def _get_default_image(self, cr, uid, is_company, context=None):
         if is_company:
-            image_path = os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'company_icon.png')
+            image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'company_icon.png')
         else:
-            image_path = os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'photo.png')
+            image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6))
         return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
 
     _defaults = {
         'active': True,
+        'lang': lambda self, cr, uid, context: context.get('lang', 'en_US'),
+        'tz': lambda self, cr, uid, context: context.get('tz', False),
         'customer': True,
         'category_id': _default_category,
         'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=c),

=== modified file 'openerp/addons/base/res/res_users.py'
--- openerp/addons/base/res/res_users.py	2012-08-07 11:08:59 +0000
+++ openerp/addons/base/res/res_users.py	2012-08-08 10:24:40 +0000
@@ -33,7 +33,6 @@
 from osv import fields,osv
 from osv.orm import browse_record
 import pooler
-import random
 from service import security
 import tools
 from tools.translate import _
@@ -96,60 +95,27 @@
 
 groups()
 
-def _lang_get(self, cr, uid, context=None):
-    obj = self.pool.get('res.lang')
-    ids = obj.search(cr, uid, [('translatable','=',True)])
-    res = obj.read(cr, uid, ids, ['code', 'name'], context=context)
-    res = [(r['code'], r['name']) for r in res]
-    return res
-
-def _tz_get(self,cr,uid, context=None):
-    return [(x, x) for x in pytz.all_timezones]
-
 class users(osv.osv):
+    """ User class. A res.users record models an OpenERP user and is different
+        from an employee.
+
+        res.users class now inherits from res.partner. The partner model is
+        used to store the data related to the partner: lang, name, address,
+        avatar, ... The user model is now dedicated to technical data.
+    """
     __admin_ids = {}
     _uid_cache = {}
+    _inherits = {
+        'res.partner': 'partner_id',
+    }
     _name = "res.users"
     _description = 'Users'
     _order = 'name'
 
-    WELCOME_MAIL_SUBJECT = u"Welcome to OpenERP"
-    WELCOME_MAIL_BODY = u"An OpenERP account has been created for you, "\
-        "\"%(name)s\".\n\nYour login is %(login)s, "\
-        "you should ask your supervisor or system administrator if you "\
-        "haven't been given your password yet.\n\n"\
-        "If you aren't %(name)s, this email reached you errorneously, "\
-        "please delete it."
-
-    def get_welcome_mail_subject(self, cr, uid, context=None):
-        """ Returns the subject of the mail new users receive (when
-        created via the res.config.users wizard), default implementation
-        is to return config_users.WELCOME_MAIL_SUBJECT
-        """
-        return self.WELCOME_MAIL_SUBJECT
-    def get_welcome_mail_body(self, cr, uid, context=None):
-        """ Returns the subject of the mail new users receive (when
-        created via the res.config.users wizard), default implementation
-        is to return config_users.WELCOME_MAIL_BODY
-        """
-        return self.WELCOME_MAIL_BODY
-
     def get_current_company(self, cr, uid):
         cr.execute('select company_id, res_company.name from res_users left join res_company on res_company.id = company_id where res_users.id=%s' %uid)
         return cr.fetchall()
 
-    def send_welcome_email(self, cr, uid, id, context=None):
-        if isinstance(id,list): id = id[0]
-        user = self.read(cr, uid, id, ['email','login','name', 'user_email'], context=context)
-        email = user['email'] or user['user_email']
-
-        ir_mail_server = self.pool.get('ir.mail_server')
-        msg = ir_mail_server.build_email(email_from=None, # take config default
-                                         email_to=[email],
-                                         subject=self.get_welcome_mail_subject(cr, uid, context=context),
-                                         body=(self.get_welcome_mail_body(cr, uid, context=context) % user))
-        return ir_mail_server.send_email(cr, uid, msg, context=context)
-
     def _set_new_password(self, cr, uid, id, name, value, args, context=None):
         if value is False:
             # Do not update the password if no value is provided, ignore silently.
@@ -164,69 +130,28 @@
 
     def _get_password(self, cr, uid, ids, arg, karg, context=None):
         return dict.fromkeys(ids, '')
-
-    def _get_image(self, cr, uid, ids, name, args, context=None):
-        result = dict.fromkeys(ids, False)
-        for obj in self.browse(cr, uid, ids, context=context):
-            result[obj.id] = tools.image_get_resized_images(obj.image)
-        return result
-    
-    def _set_image(self, cr, uid, id, name, value, args, context=None):
-        return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
     
     _columns = {
         'id': fields.integer('ID'),
-        'name': fields.char('User Name', size=64, required=True, select=True,
-                            help="The new user's real name, used for searching"
-                                 " and most listings"),
+        'active': fields.boolean('Active'),
+        'partner_id': fields.many2one('res.partner', required=True,
+            string='Related Partner', ondelete='cascade',
+            help='Partner-related data of the user'),
         'login': fields.char('Login', size=64, required=True,
-                             help="Used to log into the system"),
-        'password': fields.char('Password', size=64, invisible=True, help="Keep empty if you don't want the user to be able to connect on the system."),
+            help="Used to log into the system"),
+        'password': fields.char('Password', size=64, invisible=True,
+            help="Keep empty if you don't want the user to be able to connect on the system."),
         'new_password': fields.function(_get_password, type='char', size=64,
-                                fnct_inv=_set_new_password,
-                                string='Set Password', help="Specify a value only when creating a user or if you're changing the user's password, "
-                                                            "otherwise leave empty. After a change of password, the user has to login again."),
-        'user_email': fields.char('Email', size=64),
+            fnct_inv=_set_new_password, string='Set Password',
+            help="Specify a value only when creating a user or if you're "\
+                 "changing the user's password, otherwise leave empty. After "\
+                 "a change of password, the user has to login again."),
         'signature': fields.text('Signature', size=64),
-        'image': fields.binary("Avatar",
-            help="This field holds the image used as avatar for the "\
-                 "user. The image is base64 encoded, and PIL-supported. "\
-                 "It is limited to a 1024x1024 px image."),
-        'image_medium': fields.function(_get_image, fnct_inv=_set_image,
-            string="Medium-sized avatar", type="binary", multi="_get_image",
-            store = {
-                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
-            },
-            help="Medium-sized image of the user. It is automatically "\
-                 "resized as a 180x180 px image, with aspect ratio preserved. "\
-                 "Use this field in form views or some kanban views."),
-        'image_small': fields.function(_get_image, fnct_inv=_set_image,
-            string="Smal-sized avatar", type="binary", multi="_get_image",
-            store = {
-                'res.users': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
-            },
-            help="Small-sized image of the user. It is automatically "\
-                 "resized as a 50x50 px image, with aspect ratio preserved. "\
-                 "Use this field anywhere a small image is required."),
         'active': fields.boolean('Active'),
         'action_id': fields.many2one('ir.actions.actions', 'Home Action', help="If specified, this action will be opened at logon for this user, in addition to the standard menu."),
         'menu_id': fields.many2one('ir.actions.actions', 'Menu Action', help="If specified, the action will replace the standard menu for this user."),
         'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
-
-        # Special behavior for this field: res.company.search() will only return the companies
-        # available to the current user (should be the user's companies?), when the user_preference
-        # context is set.
-        'company_id': fields.many2one('res.company', 'Company', required=True,
-            help="The company this user is currently working for.", context={'user_preference': True}),
-
         'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'),
-        'context_lang': fields.selection(_lang_get, 'Language', required=True,
-            help="The default language used in the graphical user interface, when translations are available. To add a new language, you can use the 'Load a Translation' wizard available from the 'Administration' menu."),
-        'context_tz': fields.selection(_tz_get,  'Timezone', size=64,
-            help="The user's timezone, used to output proper date and time values inside printed reports. "
-                 "It is important to set a value for this field. You should use the same timezone "
-                 "that is otherwise used to pick and render date and time values: your computer's timezone."),
-        'date': fields.datetime('Latest Connection', readonly=True),
     }
 
     def on_change_company_id(self, cr, uid, ids, company_id):
@@ -268,8 +193,8 @@
             ids = [ids]
         res = dict.fromkeys(ids, False)
         for user in self.browse(cr, uid, ids, context=context):
-            if user.user_email:
-                res[user.id] = "%s <%s>" % (user.name, user.user_email)
+            if user.email:
+                res[user.id] = "%s <%s>" % (user.name, user.email)
         return res
 
     def _get_admin_id(self, cr):
@@ -315,16 +240,8 @@
             pass
         return result
 
-    def _get_default_image(self, cr, uid, context=None):
-        # default image file name: avatar0 -> avatar6.png, choose randomly
-        image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6))
-        return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
-
     _defaults = {
         'password' : '',
-        'context_lang': lambda self, cr, uid, context: context.get('lang', 'en_US'),
-        'context_tz': lambda self, cr, uid, context: context.get('tz', False),
-        'image': _get_default_image,
         'active' : True,
         'menu_id': _get_menu,
         'company_id': _get_company,
@@ -333,7 +250,7 @@
     }
 
     # User can write to a few of her own fields (but not her groups for example)
-    SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'user_email', 'name', 'image', 'image_medium', 'image_small']
+    SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small']
 
     def write(self, cr, uid, ids, values, context=None):
         if not hasattr(ids, '__iter__'):
@@ -398,12 +315,18 @@
     def context_get(self, cr, uid, context=None):
         user = self.browse(cr, uid, uid, context)
         result = {}
-        for k in self._columns.keys():
+        for k in self._all_columns.keys():
             if k.startswith('context_'):
+                context_key = k[8:]
+            elif k in ['lang', 'tz']:
+                context_key = k
+            else:
+                context_key = False
+            if context_key:
                 res = getattr(user,k) or False
                 if isinstance(res, browse_record):
                     res = res.id
-                result[k[8:]] = res or False
+                result[context_key] = res or False
         return result
 
     def action_get(self, cr, uid, context=None):

=== modified file 'openerp/addons/base/res/res_users_view.xml'
--- openerp/addons/base/res/res_users_view.xml	2012-08-06 15:53:25 +0000
+++ openerp/addons/base/res/res_users_view.xml	2012-08-08 10:24:40 +0000
@@ -112,8 +112,8 @@
                             <page string="Preferences">
                                 <group>
                                     <group name="preferences">
-                                        <field name="context_lang"/>
-                                        <field name="context_tz"/>
+                                        <field name="lang"/>
+                                        <field name="tz"/>
                                     </group>
                                     <group groups="base.group_no_one">
                                         <field name="action_id"/>
@@ -121,7 +121,7 @@
                                     </group>
                                 </group>
                                 <group>
-                                    <field name="user_email" widget="email"/>
+                                    <field name="email" widget="email"/>
                                     <field name="signature"/>
                                 </group>
                             </page>
@@ -146,7 +146,7 @@
                 <tree string="Users">
                     <field name="name"/>
                     <field name="login"/>
-                    <field name="context_lang"/>
+                    <field name="lang"/>
                     <field name="date"/>
                 </tree>
             </field>
@@ -210,15 +210,15 @@
                         (<field name="login" readonly="1" class="oe_inline"/>)
                     </h1>
                     <group name="preferences" col="4">
-                        <field name="context_lang" readonly="0"/>
+                        <field name="lang" readonly="0"/>
                         <field name="company_id" readonly="0"
                             groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/>
-                        <field name="context_tz" readonly="0"/>
+                        <field name="tz" readonly="0"/>
                         <field name="company_id" widget="selection" readonly="0"
                             groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/>
                     </group>
                     <group string="Email Preferences">
-                        <field name="user_email" widget="email" readonly="0"/>
+                        <field name="email" widget="email" readonly="0"/>
                         <field name="signature" readonly="0"/>
                     </group>
                     </sheet>

=== renamed file 'openerp/addons/base/res/company_icon.png' => 'openerp/addons/base/static/src/img/company_icon.png'
=== modified file 'openerp/service/web_services.py'
--- openerp/service/web_services.py	2012-03-22 15:05:06 +0000
+++ openerp/service/web_services.py	2012-08-08 10:24:40 +0000
@@ -75,10 +75,10 @@
             mids = modobj.search(cr, 1, [('state', '=', 'installed')])
             modobj.update_translations(cr, 1, mids, lang)
 
-        cr.execute('UPDATE res_users SET password=%s, context_lang=%s, active=True WHERE login=%s', (
+        cr.execute('UPDATE res_users SET password=%s, lang=%s, active=True WHERE login=%s', (
             user_password, lang, 'admin'))
         cr.execute('SELECT login, password, name ' \
-                   '  FROM res_users ' \
+                   ' FROM res_users ' \
                    ' ORDER BY login')
         serv.actions[id].update(users=cr.dictfetchall(), clean=True)
         cr.commit()
@@ -425,7 +425,7 @@
 The whole source code is distributed under the terms of the
 GNU Public Licence.
 
-(c) 2003-TODAY, Fabien Pinckaers - Tiny sprl''')
+(c) 2003-TODAY - OpenERP SA''')
 
         if extended:
             return info, release.version

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to