← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~openerp-dev/openobject-server/niv-dev-server into lp:openobject-server

 

Nicolas Vanhoren (OpenERP) has proposed merging lp:~openerp-dev/openobject-server/niv-dev-server into lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)


Complete refactoring of the old maintenance sub-module in base
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/niv-dev-server/+merge/41563
Your team OpenERP R&D Team is subscribed to branch lp:~openerp-dev/openobject-server/niv-dev-server.
=== modified file '.bzrignore'
--- .bzrignore	2009-12-02 10:01:14 +0000
+++ .bzrignore	2010-11-23 10:03:56 +0000
@@ -18,3 +18,6 @@
 build/
 bin/yolk
 bin/pil*.py
+.project
+.pydevproject
+.settings

=== modified file 'bin/addons/base/__init__.py'
--- bin/addons/base/__init__.py	2009-10-20 10:52:23 +0000
+++ bin/addons/base/__init__.py	2010-11-23 10:03:56 +0000
@@ -22,7 +22,7 @@
 import ir
 import module
 import res
-import maintenance
+import publisher_warranty
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 

=== modified file 'bin/addons/base/__openerp__.py'
--- bin/addons/base/__openerp__.py	2010-10-18 19:24:50 +0000
+++ bin/addons/base/__openerp__.py	2010-11-23 10:03:56 +0000
@@ -71,11 +71,12 @@
 
         'res/ir_property_view.xml',
         'security/base_security.xml',
-        'maintenance/maintenance_view.xml',
+        'publisher_warranty/publisher_warranty_view.xml',
 
         'security/ir.model.access.csv',
         'res/res_widget_view.xml',
         'res/res_widget_data.xml',
+        'publisher_warranty/publisher_warranty_data.xml',
     ],
     'demo_xml': [
         'base_demo.xml',

=== modified file 'bin/addons/base/ir/__init__.py'
--- bin/addons/base/ir/__init__.py	2010-11-10 15:04:48 +0000
+++ bin/addons/base/ir/__init__.py	2010-11-23 10:03:56 +0000
@@ -34,6 +34,7 @@
 import workflow
 import ir_rule
 import wizard
+import ir_config_parameter
 import osv_memory_autovacuum
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'bin/addons/base/ir/ir_config_parameter.py'
--- bin/addons/base/ir/ir_config_parameter.py	1970-01-01 00:00:00 +0000
+++ bin/addons/base/ir/ir_config_parameter.py	2010-11-23 10:03:56 +0000
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+"""
+A module to store some configuration parameters relative to a whole database.
+"""
+
+from osv import osv,fields
+import uuid
+import datetime
+from tools import misc
+
+"""
+A dictionary holding some configuration parameters to be initialized when the database is created.
+"""
+_default_parameters = {
+    "database.uuid": lambda: str(uuid.uuid1()),
+    "database.create_date": lambda: datetime.datetime.now().strftime(misc.DEFAULT_SERVER_DATETIME_FORMAT),
+}
+
+class ir_config_parameter(osv.osv):
+    """ An osv to old configuration parameters for a given database.
+    
+    To be short, it's just a global dictionary of strings stored in a table. """
+    
+    _name = 'ir.config_parameter'
+    
+    _columns = {
+        # The key of the configuration parameter.
+        'key': fields.char('Key', size=256, required=True, select=1),
+        # The value of the configuration parameter.
+        'value': fields.text('Value', required=True),
+    }
+    
+    _sql_constraints = [
+        ('key_uniq', 'unique (key)', 'Key must be unique.')
+    ]
+    
+    def init(self, cr):
+        """
+        Initializes the parameters listed in _default_parameters.
+        """
+        for key, func in _default_parameters.iteritems():
+            ids = self.search(cr, 1, [('key','=',key)])
+            if not ids:
+                self.set_param(cr, 1, key, func())
+
+    def get_param(self, cr, uid, key, context=None):
+        """ Get the value of a parameter.
+        
+        @param key: The key of the parameter.
+        @type key: string
+        @return: The value of the parameter, False if it does not exist.
+        @rtype: string
+        """
+        ids = self.search(cr, uid, [('key','=',key)], context=context)
+        if not ids:
+            return False
+        param = self.browse(cr, uid, ids[0], context=context)
+        value = param.value
+        return value
+    
+    def set_param(self, cr, uid, key, value, context=None):
+        """ Set the value of a parameter.
+        
+        @param key: The key of the parameter.
+        @type key: string
+        @param value: The value of the parameter.
+        @type value: string
+        @return: Return the previous value of the parameter of False if it did
+        not existed.
+        @rtype: string
+        """
+        ids = self.search(cr, uid, [('key','=',key)], context=context)
+        if ids:
+            param = self.browse(cr, uid, ids[0], context=context)
+            old = param.value
+            self.write(cr, uid, ids, {'value': value}, context=context)
+            return old
+        else:
+            self.create(cr, uid, {'key': key, 'value': value}, context=context)
+            return False
+
+ir_config_parameter()

=== modified file 'bin/addons/base/ir/ir_cron.py'
--- bin/addons/base/ir/ir_cron.py	2010-10-04 14:39:04 +0000
+++ bin/addons/base/ir/ir_cron.py	2010-11-23 10:03:56 +0000
@@ -145,7 +145,8 @@
 
     def restart(self, dbname):
         self.cancel(dbname)
-        self._poolJobs(dbname)
+        # Reschedule cron processing job asap, but not in the current thread
+        self.setAlarm(self._poolJobs, time.time(), dbname, dbname)
 
     def create(self, cr, uid, vals, context=None):
         res = super(ir_cron, self).create(cr, uid, vals, context=context)

=== removed directory 'bin/addons/base/maintenance'
=== removed file 'bin/addons/base/maintenance/__init__.py'
--- bin/addons/base/maintenance/__init__.py	2009-10-20 10:52:23 +0000
+++ bin/addons/base/maintenance/__init__.py	1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#    
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
-#
-##############################################################################
-
-import maintenance
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

=== removed file 'bin/addons/base/maintenance/maintenance.py'
--- bin/addons/base/maintenance/maintenance.py	2009-10-20 10:52:23 +0000
+++ bin/addons/base/maintenance/maintenance.py	1970-01-01 00:00:00 +0000
@@ -1,206 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#    
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
-#
-##############################################################################
-
-from osv import osv, fields
-import pooler
-import time
-import netsvc
-
-from tools.misc import debug
-from tools.misc import ustr
-from tools.translate import _
-import tools.maintenance as tm
-
-class maintenance_contract_module(osv.osv):
-    _name ="maintenance.contract.module"
-    _description = "maintenance contract modules"
-    _columns = {
-        'name' : fields.char('Name', size=128, required=True),
-        'version': fields.char('Version', size=64,),
-    }
-
-maintenance_contract_module()
-
-class maintenance_contract(osv.osv):
-    _name = "maintenance.contract"
-    _description = "Maintenance Contract"
-
-    def _get_valid_contracts(self, cr, uid):
-        return [contract for contract in self.browse(cr, uid, self.search(cr, uid, [])) if contract.state == 'valid']
-
-    def status(self, cr, uid):
-        covered_modules, uncovered_modules = set(), set()
-
-        status = 'none'
-        for contract in self._get_valid_contracts(cr, uid):
-            covered_modules.update([m.name for m in contract.module_ids])
-        
-        if covered_modules:
-            modobj = self.pool.get('ir.module.module')
-            modids = modobj.search(cr, uid, [('state', '=', 'installed')])
-            uncovered_modules = set(m.name for m in modobj.browse(cr, uid, modids)) - covered_modules
-            status = ['full', 'partial'][len(uncovered_modules) > 0]
-        
-        return {
-            'status': status,
-            'uncovered_modules': list(uncovered_modules),
-        }
-    
-    def send(self, cr, uid, tb, explanations, remarks=None):
-        status = self.status(cr, uid)
-        if status['status'] != 'full':
-            raise osv.except_osv(_('Error'), _("Your can't submit bug reports due to uncovered modules: %s") % (', '.join(status['uncovered_modules']),))
-        
-        dbmsg = _('This error occurs on database %s') % (cr.dbname,)
-        if not remarks:
-            remarks = dbmsg
-        else:
-            remarks += '\n\n-----\n' + dbmsg
-
-        valid_contracts = self._get_valid_contracts(cr, uid)
-
-        crm_case_id = None
-        rc = None
-        try:
-            for contract in valid_contracts: 
-                rc = tm.remote_contract(contract.name, contract.password)
-                if rc.id:
-                    break
-                rc = None
-        
-            if not rc:
-                raise osv.except_osv(_('Error'), _('Unable to find a valid contract'))
-            
-            origin = 'client'
-            crm_case_id = rc.submit(rc.id, tb, explanations, remarks or '', origin)
-
-        except tm.RemoteContractException, rce:
-            netsvc.Logger().notifyChannel('maintenance', netsvc.LOG_INFO, rce)
-        except osv.except_osv:
-            raise
-        except:
-            pass
-        
-        cid = rc and rc.name or valid_contracts[0].name
-        try:
-            # as backup, put it also in another database...
-            import urllib
-            args = urllib.urlencode({
-                'contract_id': cid,
-                'crm_case_id': crm_case_id or 0,
-                'explanation': explanations,
-                'remark': remarks or '',
-                'tb': tb,
-            })
-            uo = urllib.urlopen('http://www.openerp.com/scripts/maintenance.php', args)
-            submit_result = uo.read()
-            debug(submit_result)
-            uo.close()
-        except:
-            if not crm_case_id:
-                # TODO schedule a retry (ir.cron)
-                return False
-        return True
-
-    def _valid_get(self, cr, uid, ids, field_name, arg, context=None):
-        res = {}
-        for contract in self.browse(cr, uid, ids, context=context):
-            res[contract.id] = ("unvalid", "valid")[contract.date_stop >= time.strftime('%Y-%m-%d')]
-        return res
-
-    _columns = {
-        'name' : fields.char('Contract ID', size=256, required=True, readonly=True),
-        'password' : fields.char('Password', size=64, invisible=True, required=True, readonly=True),
-        'date_start' : fields.date('Starting Date', readonly=True),
-        'date_stop' : fields.date('Ending Date', readonly=True),
-        'module_ids' : fields.many2many('maintenance.contract.module', 'maintenance_contract_module_rel', 'contract_id', 'module_id', 'Covered Modules', readonly=True),
-        'state' : fields.function(_valid_get, method=True, string="State", type="selection", selection=[('valid', 'Valid'),('unvalid', 'Unvalid')], readonly=True),
-        'kind' : fields.selection([('full', 'Full'),('partial', 'Partial')], 'Kind', required=True, readonly=True),
-    }
-    _defaults = {
-        'password' : lambda obj,cr,uid,context={} : '',
-    }
-    _sql_constraints = [
-        ('uniq_name', 'unique(name)', "Your maintenance contract is already subscribed in the system !")
-    ]
-
-maintenance_contract()
-
-
-class maintenance_contract_wizard(osv.osv_memory):
-    _name = 'maintenance.contract.wizard'
-
-    _columns = {
-        'name' : fields.char('Contract ID', size=256, required=True ),
-        'password' : fields.char('Password', size=64, required=True),
-        'state' : fields.selection([('draft', 'Draft'),('validated', 'Validated'),('unvalidated', 'Unvalidated')], 'States'),
-    }
-
-    _defaults = {
-        'state' : lambda *a: 'draft',
-    }
-
-    def action_validate(self, cr, uid, ids, context=None):
-        if not ids:
-            return False
-
-        module_proxy = self.pool.get('ir.module.module')
-        module_ids = module_proxy.search(cr, uid, [('state', '=', 'installed')])
-        modules = module_proxy.read(cr, uid, module_ids, ['name', 'installed_version'])
-
-        contract = self.read(cr, uid, ids, ['name', 'password'])[0]
-        
-        try:
-            contract_info = tm.remote_contract(contract['name'], contract['password'], modules)
-        except tm.RemoteContractException, rce:
-            raise osv.except_osv(_('Error'), ustr(rce))
-
-        is_ok = contract_info['status'] in ('partial', 'full')
-        if is_ok:
-            module_ids = []
-            if contract_info['modules_with_contract']:
-                for name, version in contract_info['modules_with_contract']:
-                    contract_module = self.pool.get('maintenance.contract.module')
-                    res = contract_module.search(cr, uid, [('name', '=', name),('version', '=', version)])
-                    if not res:
-                        id = contract_module.create(cr, uid, { 'name' : name, 'version' : version } )
-                    else:
-                        id = res[0]
-                    module_ids.append(id)
-
-            self.pool.get('maintenance.contract').create(
-                cr, 
-                uid, {
-                    'name' : contract['name'],
-                    'password' : contract['password'],
-                    'date_start' : contract_info['date_from'],
-                    'date_stop' : contract_info['date_to'],
-                    'kind' : contract_info['status'],
-                    'module_ids' : [(6,0,module_ids)],
-                }
-            )
-
-        return self.write(cr, uid, ids, {'state' : ('unvalidated', 'validated')[is_ok] }, context=context)
-
-maintenance_contract_wizard()
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-

=== removed file 'bin/addons/base/maintenance/maintenance_security.xml'
--- bin/addons/base/maintenance/maintenance_security.xml	2010-06-12 16:21:33 +0000
+++ bin/addons/base/maintenance/maintenance_security.xml	1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
-<data noupdate="0">
-
-</data>
-</openerp>

=== removed file 'bin/addons/base/maintenance/maintenance_view.xml'
--- bin/addons/base/maintenance/maintenance_view.xml	2010-10-15 06:54:45 +0000
+++ bin/addons/base/maintenance/maintenance_view.xml	1970-01-01 00:00:00 +0000
@@ -1,131 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
-    <data>
-
-        <record id="maintenance_contract_tree_view" model="ir.ui.view">
-            <field name="name">maintenance.contract.tree</field>
-            <field name="model">maintenance.contract</field>
-            <field name="type">tree</field>
-            <field name="arch" type="xml">
-                <tree string="Maintenance Contract">
-                    <field name="name"/>
-                    <field name="date_start"/>
-                    <field name="date_stop"/>
-                    <field name="state" />
-                </tree>
-            </field>
-        </record>
-
-        <record id="maintenance_contract_form_view" model="ir.ui.view">
-            <field name="name">maintenance.contract.form</field>
-            <field name="model">maintenance.contract</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Maintenance Contract">
-                    <group col="6" colspan="4">
-	                    <field name="name"/>
-	                    <field name="date_start"/>
-	                    <field name="date_stop"/>
-	                </group>
-                    <separator string="Covered Modules" colspan="4"/>
-                    <field name="module_ids" nolabel="1" colspan="4">
-                        <tree string="Covered Modules">
-                            <field name="name" />
-                            <field name="version" />
-                        </tree>
-                    </field>
-                    <field name="state" colspan="4"/>
-                </form>
-            </field>
-        </record>
-
-        <record id="maintenance_contract_search_view" model="ir.ui.view">
-            <field name="name">maintenance.contract.search</field>
-            <field name="model">maintenance.contract</field>
-            <field name="type">search</field>
-            <field name="arch" type="xml">
-                <search string="Maintenance Contract">
-                    <field name="name"/>
-                    <field name="date_start"/>
-                    <field name="date_stop"/>
-                </search>
-            </field>
-        </record>
-
-        <record id="maintenance_contract_view_calendar" model="ir.ui.view">
-            <field name="name">maintenance.contract.calendar</field>
-            <field name="model">maintenance.contract</field>
-            <field name="type">calendar</field>
-            <field name="arch" type="xml">
-                <calendar string="Maintenance Contract" date_start="date_start" color="state">
-                    <field name="name"/>
-                    <field name="state"/>
-                </calendar>
-            </field>
-        </record>
-
-        <record id="action_maintenance_contract_form" model="ir.actions.act_window">
-            <field name="name">Maintenance Contracts</field>
-            <field name="type">ir.actions.act_window</field>
-            <field name="res_model">maintenance.contract</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">tree,form,calendar</field>
-            <field name="search_view_id" ref="maintenance_contract_search_view"/>
-        </record>
-
-        <menuitem
-            name="Maintenance"
-            id="maintenance"
-            parent="base.menu_administration" groups="base.group_extended"/>
-
-        <menuitem
-            action="action_maintenance_contract_form"
-            id="menu_maintenance_contract"
-            parent="maintenance"/>
-
-        <record id="maintenance_contract_add_wizard" model="ir.ui.view">
-            <field name="name">maintenance.contract.add.wizard</field>
-            <field name="model">maintenance.contract.wizard</field>
-            <field name="type">form</field>
-            <field name="arch" type="xml">
-                <form string="Add Maintenance Contract" col="2">
-                        <group col="1">
-                        <separator string="Add Maintenance Contract" />
-                        <group states="draft">
-                            <field name="name" width="250" />
-                            <newline />
-                            <field name="password" password="True" />
-                            <field name="state" invisible="1" />
-                        </group>
-                        <group states="validated">
-                            <label string="Maintenance contract added !"/>
-                        </group>
-                        <group states="unvalidated">
-                            <label string="Could you check your contract information ?" />
-                        </group>
-                    </group>
-                    <group colspan="4">
-                        <button type="object" string="_Cancel" icon="gtk-cancel" special="cancel" states="draft"/>
-                        <button type="object" string="_Validate" icon="gtk-apply" name="action_validate" states="draft"/>
-                        <button type="object" string="_Close" icon="gtk-close" special="cancel" states="validated,unvalidated"/>
-                    </group>
-                </form>
-            </field>
-        </record>
-
-        <record id="action_maintenance_contract_add_wizard" model="ir.actions.act_window">
-            <field name="name">Add Maintenance Contract</field>
-            <field name="type">ir.actions.act_window</field>
-            <field name="res_model">maintenance.contract.wizard</field>
-            <field name="view_type">form</field>
-            <field name="view_mode">form</field>
-            <field name="target">new</field>
-        </record>
-
-        <menuitem
-            action="action_maintenance_contract_add_wizard"
-            id="menu_maintenance_contract_add"
-            parent="maintenance" />
-
-    </data>
-</openerp>

=== added directory 'bin/addons/base/publisher_warranty'
=== added file 'bin/addons/base/publisher_warranty/__init__.py'
--- bin/addons/base/publisher_warranty/__init__.py	1970-01-01 00:00:00 +0000
+++ bin/addons/base/publisher_warranty/__init__.py	2010-11-23 10:03:56 +0000
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#    
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#
+##############################################################################
+
+import publisher_warranty
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+

=== added file 'bin/addons/base/publisher_warranty/publisher_warranty.py'
--- bin/addons/base/publisher_warranty/publisher_warranty.py	1970-01-01 00:00:00 +0000
+++ bin/addons/base/publisher_warranty/publisher_warranty.py	2010-11-23 10:03:56 +0000
@@ -0,0 +1,293 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#    
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
+#
+##############################################################################
+"""
+Module to handle publisher warranty contracts as well as notifications from
+OpenERP.
+"""
+
+from osv import osv, fields
+import logging
+from tools.translate import _
+import urllib
+from tools.safe_eval import safe_eval
+import pooler
+from tools.config import config
+import release
+import datetime
+
+_logger = logging.getLogger(__name__)
+
+class publisher_warranty_contract(osv.osv):
+    """
+    Osv representing a publisher warranty contract.
+    """
+    _name = "publisher_warranty.contract"
+
+    def _get_valid_contracts(self, cr, uid):
+        """
+        Return the list of the valid contracts encoded in the system.
+        
+        @return: A list of contracts
+        @rtype: list of publisher_warranty.contract browse records
+        """
+        return [contract for contract in self.browse(cr, uid, self.search(cr, uid, []))
+                if contract.state == 'valid']
+    
+    def status(self, cr, uid):
+        """ Method called by the client to check availability of publisher warranty contract. """
+        
+        contracts = self._get_valid_contracts(cr, uid)
+        return {
+            'status': "full" if contracts else "none" ,
+            'uncovered_modules': list(),
+        }
+    
+    def send(self, cr, uid, tb, explanations, remarks=None):
+        """ Method called by the client to send a problem to the publisher warranty server. """
+        
+        if not remarks:
+            remarks = ""
+
+        valid_contracts = self._get_valid_contracts(cr, uid)
+        valid_contract = valid_contracts[0]
+        
+        try:
+            origin = 'client'
+            dbuuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
+            db_create_date = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
+            
+            msg = {'contract_name': valid_contract.name,
+                'tb': tb,
+                'explanations': explanations,
+                'remarks': remarks,
+                'origin': origin,
+                'dbname': cr.dbname,
+                'dbuuid': dbuuid,
+                'db_create_date': db_create_date}
+            
+            uo = urllib.urlopen(config.get("publisher_warranty_url"),
+                                    urllib.urlencode({'arg0': msg, "action": "send",}))
+            try:
+                submit_result = uo.read()
+            finally:
+                uo.close()
+            
+            result = safe_eval(submit_result)
+            
+            crm_case_id = result
+            
+            if not crm_case_id:
+                return False
+            
+        except osv.except_osv:
+            raise
+        except:
+            _logger.warning("Error sending problem report", exc_info=1)
+            raise osv.except_osv("Connection error", "An error occured during the connection " +
+                                 "with the publisher warranty server.")
+        
+        return True
+    
+    def check_validity(self, cr, uid, ids, context={}):
+        """
+        Check the validity of a publisher warranty contract. This method just call send_ping() but checks
+        some more things, so it can be called from a user interface.
+        """
+        contract_id = ids[0]
+        contract = self.browse(cr, uid, contract_id)
+        state = contract.state
+        validated = state != "unvalidated"
+        
+        self.send_ping(cr, uid, ids, cron_mode=False, context=context)
+        
+        contract = self.browse(cr, uid, contract_id)
+        validated2 = contract.state != "unvalidated"
+        if not validated and not validated2:
+            raise osv.except_osv(_("Contract validation error"),
+                                 _("Please check your publisher warranty contract name and validity."))
+    
+    def send_ping(self, cr, uid, ids, cron_mode=True, context={}):
+        """
+        Send a message to OpenERP's publisher warranty server to check the validity of
+        the contracts, get notifications, etc...
+        
+        @param cron_mode: If true, catch all exceptions (appropriate for usage in a cron).
+        @type cron_mode: boolean
+        """
+        try:
+            try:
+                result = send_ping(cr, uid)
+            except:
+                _logger.debug("Exception while sending a ping", exc_info=1)
+                raise osv.except_osv(_("Error"), _("Error during communication with the publisher warranty server."))
+            
+            contracts = result["contracts"]
+            for contract in contracts:
+                c_id = self.search(cr, uid, [("name","=",contract)])[0]
+                date_from = contracts[contract][0]
+                date_to = contracts[contract][1]
+                state = contracts[contract][2]
+                self.write(cr, uid, c_id, {
+                    "date_start": date_from,
+                    "date_stop": date_to,
+                    "state": state,
+                })
+            
+            if cron_mode and result["interval_type"] and result["interval_number"]:
+                modosv = self.pool.get("ir.model.data")
+                sched_id = modosv.get_object_reference(cr, uid, "base", "ir_cron_ping_scheduler")[1]
+                cronosv = self.pool.get("ir.cron")
+                cronosv.write(cr, uid, sched_id, {
+                    "interval_type": result["interval_type"],
+                    "interval_number": result["interval_number"],
+                })
+            
+            self.pool.get('res.log').create(cr, uid,
+                    {
+                        'name': result["message"],
+                        'res_model': "Maintenance Notifications",
+                        "read": True,
+                    },
+                    context=context
+            )
+        except:
+            _logger.debug("Exception while interpreting the result of a ping", exc_info=1)
+            if cron_mode:
+                return False # same as before
+            else:
+                raise
+            
+        return True
+    
+    def get_last_user_message(self, cr, uid, context={}):
+        ids = self.pool.get('res.log').search(cr, uid, [("res_model", "=", "Maintenance Notifications")]
+                                        , order="create_date desc", limit=1)
+        if not ids:
+            return False
+        to_return = self.pool.get('res.log').browse(cr, uid, ids[0]).name
+        return to_return
+
+    _columns = {
+        'name' : fields.char('Contract Name', size=384, required=True),
+        'date_start' : fields.date('Starting Date', readonly=True),
+        'date_stop' : fields.date('Ending Date', readonly=True),
+        'state' : fields.selection([('unvalidated', 'Unvalidated'), ('valid', 'Valid')
+                            , ('terminated', 'Terminated'), ('canceled', 'Canceled')], string="State", readonly=True),
+        'kind' : fields.char('Kind', size=64, readonly=True),
+    }
+    
+    _defaults = {
+        'state': 'unvalidated',
+    }
+    
+    _sql_constraints = [
+        ('uniq_name', 'unique(name)', "Your publisher warranty contract is already subscribed in the system !")
+    ]
+
+publisher_warranty_contract()
+
+class maintenance_contract(osv.osv_memory):
+    """ Old osv we only keep for compatibility with the clients. """
+    
+    _name = "maintenance.contract"
+    
+    def status(self, cr, uid):
+        return self.pool.get("publisher_warranty.contract").status(cr, uid)
+        
+    def send(self, cr, uid, tb, explanations, remarks=None):
+        return self.pool.get("publisher_warranty.contract").send(cr, uid, tb, explanations, remarks)
+    
+maintenance_contract()
+
+class publisher_warranty_contract_wizard(osv.osv_memory):
+    """
+    A wizard osv to help people entering a publisher warranty contract.
+    """
+    _name = 'publisher_warranty.contract.wizard'
+
+    _columns = {
+        'name' : fields.char('Contract Name', size=256, required=True ),
+        'state' : fields.selection([("draft", "Draft"), ("finished", "Finished")])
+    }
+    
+    _defaults = {
+        "state": "draft",
+    }
+
+    def action_validate(self, cr, uid, ids, context=None):
+        if not ids:
+            return False
+
+        wiz = self.browse(cr, uid, ids[0])
+        c_name = wiz.name
+        
+        contract_osv = self.pool.get("publisher_warranty.contract")
+        contracts = contract_osv.search(cr, uid, [("name","=",c_name)])
+        if contracts:
+            raise osv.except_osv(_("Error"), _("That contract is already registered in the system."))
+        
+        contract_id = contract_osv.create(cr, uid, {
+            "name": c_name,
+            "state": "unvalidated",
+        })
+        
+        contract_osv.check_validity(cr, uid, [contract_id])
+        
+        self.write(cr, uid, ids, {"state": "finished"})
+        
+        return True
+
+
+publisher_warranty_contract_wizard()
+
+def send_ping(cr, uid):
+    """
+    Utility method to send a publisher warranty ping.
+    """
+    pool = pooler.get_pool(cr.dbname)
+    
+    dbuuid = pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
+    db_create_date = pool.get('ir.config_parameter').get_param(cr, uid, 'database.create_date')
+    nbr_users = pool.get("res.users").search(cr, uid, [], count=True)
+    contractosv = pool.get('publisher_warranty.contract')
+    contracts = contractosv.browse(cr, uid, contractosv.search(cr, uid, []))
+    msg = {
+        "dbuuid": dbuuid,
+        "nbr_users": nbr_users,
+        "dbname": cr.dbname,
+        "db_create_date": db_create_date,
+        "version": release.version,
+        "contracts": [c.name for c in contracts],
+    }
+    
+    uo = urllib.urlopen(config.get("publisher_warranty_url"),
+                        urllib.urlencode({'arg0': msg, "action": "update",}))
+    try:
+        submit_result = uo.read()
+    finally:
+        uo.close()
+    
+    result = safe_eval(submit_result)
+    
+    return result
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+

=== added file 'bin/addons/base/publisher_warranty/publisher_warranty_data.xml'
--- bin/addons/base/publisher_warranty/publisher_warranty_data.xml	1970-01-01 00:00:00 +0000
+++ bin/addons/base/publisher_warranty/publisher_warranty_data.xml	2010-11-23 10:03:56 +0000
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+
+		<record id="ir_cron_ping_scheduler" model="ir.cron">
+			<field name="name">Update Data Scheduler</field>
+			<field eval="True" name="active" />
+			<field name="user_id" ref="base.user_root" />
+			<field name="interval_number">1</field>
+			<field name="interval_type">weeks</field>
+			<field name="numbercall">-1</field>
+			<field eval="True" name="doall" />
+			<field eval="'publisher_warranty.contract'" name="model" />
+			<field eval="'send_ping'" name="function" />
+			<field eval="'(None,)'" name="args" />
+		</record>
+    
+    </data>
+</openerp>
\ No newline at end of file

=== added file 'bin/addons/base/publisher_warranty/publisher_warranty_view.xml'
--- bin/addons/base/publisher_warranty/publisher_warranty_view.xml	1970-01-01 00:00:00 +0000
+++ bin/addons/base/publisher_warranty/publisher_warranty_view.xml	2010-11-23 10:03:56 +0000
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <record id="publisher_warranty_contract_tree_view" model="ir.ui.view">
+            <field name="name">publisher_warranty.contract.tree</field>
+            <field name="model">publisher_warranty.contract</field>
+            <field name="type">tree</field>
+            <field name="arch" type="xml">
+                <tree string="Publisher Warranty Contract">
+                    <field name="name"/>
+                    <field name="date_start"/>
+                    <field name="date_stop"/>
+                    <field name="state" />
+                </tree>
+            </field>
+        </record>
+
+        <record id="publisher_warranty_contract_form_view" model="ir.ui.view">
+            <field name="name">publisher_warranty.contract.form</field>
+            <field name="model">publisher_warranty.contract</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Publisher Warranty Contract">
+                    <group col="2" colspan="4">
+                        <group col="2">
+                    		<field name="name"/>
+                        </group>
+                        <group col="2">
+                    		<field name="date_start"/>
+                    		<field name="date_stop"/>
+                    	</group>
+                        <group col="2">
+                            <field name="state"/>
+                            <field name="kind"/>
+                        </group>
+                        <group col="2">
+                        	<button name="check_validity" string="Validate" type="object"
+                        	attrs="{'invisible':[('state','in',['valid', 'terminated', 'canceled'])]}"/>
+                        	<button name="check_validity" string="Refresh Validation Dates" type="object"
+                        	attrs="{'invisible':[('state','in',['unvalidated'])]}"/>
+                        </group>
+                	</group>
+                </form>
+            </field>
+        </record>
+
+        <record id="publisher_warranty_contract_search_view" model="ir.ui.view">
+            <field name="name">publisher_warranty.contract.search</field>
+            <field name="model">publisher_warranty.contract</field>
+            <field name="type">search</field>
+            <field name="arch" type="xml">
+                <search string="Publisher Warranty Contract">
+                    <field name="name"/>
+                    <field name="date_start"/>
+                    <field name="date_stop"/>
+                </search>
+            </field>
+        </record>
+
+        <record id="publisher_warranty_contract_view_calendar" model="ir.ui.view">
+            <field name="name">publisher_warranty.contract.calendar</field>
+            <field name="model">publisher_warranty.contract</field>
+            <field name="type">calendar</field>
+            <field name="arch" type="xml">
+                <calendar string="Maintenance Contract" date_start="date_start" color="state">
+                    <field name="name"/>
+                    <field name="state"/>
+                </calendar>
+            </field>
+        </record>
+
+        <record id="action_publisher_warranty_contract_form" model="ir.actions.act_window">
+            <field name="name">Publisher Warranty Contracts</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">publisher_warranty.contract</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form,calendar</field>
+            <field name="search_view_id" ref="publisher_warranty_contract_search_view"/>
+        </record>
+
+        <menuitem name="Publisher Warranty" id="publisher_warranty"
+            parent="base.menu_administration" groups="base.group_extended"/>
+
+        <menuitem action="action_publisher_warranty_contract_form" id="menu_publisher_warranty_contract" parent="publisher_warranty"/>
+
+
+        <record id="publisher_warranty_contract_add_wizard" model="ir.ui.view">
+            <field name="name">publisher_warranty.contract.add.wizard</field>
+            <field name="model">publisher_warranty.contract.wizard</field>
+            <field name="type">form</field>
+            <field name="arch" type="xml">
+                <form string="Add Publisher Warranty Contract" col="2">
+                	<field name="state" invisible="1"/>
+                	<group states="draft">
+	                    <group col="1">
+	                        <separator string="Add Publisher Warranty Contract" />
+	                        <field name="name" width="250" />
+	                    </group>
+	                    <group colspan="4">
+	                        <button type="object" string="Cancel" icon="gtk-cancel" special="cancel"/>
+	                        <button type="object" string="Validate" icon="gtk-apply" name="action_validate"/>
+	                    </group>
+                    </group>
+                	<group states="finished">
+	                    <label string="The contract was correctly added." colspan="4" />
+	                    <group colspan="4">
+	                    	<button type="object" string="Ok" icon="gtk-apply" special="cancel"/>
+	                    </group>
+                	</group>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_publisher_warranty_contract_add_wizard" model="ir.actions.act_window">
+            <field name="name">Add Publisher Warranty Contract</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">publisher_warranty.contract.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+        <menuitem
+            action="action_publisher_warranty_contract_add_wizard"
+            id="menu_publisher_warranty_contract_add"
+            parent="publisher_warranty" />
+            
+        <record id="publisher_warranty_res_log_act_window" model="ir.actions.act_window">
+            <field name="name">Notifications</field>
+            <field name="res_model">res.log</field>
+            <field name="view_type">form</field>
+            <field name="context">{'search_default_my': 1}</field>
+            <field name="domain">[('res_model','=','Maintenance Notifications')]</field>
+        </record>
+        
+        <menuitem
+            action="publisher_warranty_res_log_act_window"
+            id="menu_publisher_warranty_res_log"
+            parent="publisher_warranty"/>
+
+    </data>
+</openerp>

=== modified file 'bin/addons/base/security/ir.model.access.csv'
--- bin/addons/base/security/ir.model.access.csv	2010-10-17 21:30:11 +0000
+++ bin/addons/base/security/ir.model.access.csv	2010-11-23 10:03:56 +0000
@@ -112,8 +112,7 @@
 "access_res_payterm_group_system","res_payterm_group_system","model_res_payterm","group_system",1,1,1,1
 "access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1
 "access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
-"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_system",1,1,1,1
-"access_maintenance_contract_module","maintenance.contract.module","model_maintenance_contract_module","group_system",1,1,1,1
+"access_publisher_warranty_group_user","publisher_warranty_contract group_user","model_publisher_warranty_contract","group_system",1,1,1,1
 "access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0
 "access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
 "access_ir_filter all","ir_filters all","model_ir_filters",,1,0,0,0
@@ -123,3 +122,4 @@
 "access_res_widget","res.widget","model_res_widget","group_erp_manager",1,1,1,1
 "access_res_widget_user","res.widget.user","model_res_widget",,1,0,0,0
 "access_res_log_all","res.log","model_res_log",,1,1,1,1
+"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0

=== modified file 'bin/tools/config.py'
--- bin/tools/config.py	2010-11-17 12:39:28 +0000
+++ bin/tools/config.py	2010-11-23 10:03:56 +0000
@@ -31,8 +31,8 @@
     try:
         from OpenSSL import SSL
         import socket
-
-        return hasattr(socket, 'ssl')
+        
+        return hasattr(socket, 'ssl') and hasattr(SSL, "Connection")
     except:
         return False
 
@@ -91,7 +91,10 @@
             'static_http_url_prefix': None,
             'secure_cert_file': 'server.cert',
             'secure_pkey_file': 'server.pkey',
+            'publisher_warranty_url': 'http://www.openerp.com/publisher-warranty',
         }
+        
+        self.blacklist_for_save = set(["publisher_warranty_url"])
 
         self.misc = {}
         self.config_file = fname
@@ -224,7 +227,7 @@
         parser.add_option_group(security)
 
     def parse_config(self):
-        (opt, args) = self.parser.parse_args()
+        opt = self.parser.parse_args()[0]
 
         def die(cond, msg):
             if cond:
@@ -317,7 +320,7 @@
             # If an explicit TZ was provided in the config, make sure it is known
             try:
                 import pytz
-                tz = pytz.timezone(self.options['timezone'])
+                pytz.timezone(self.options['timezone'])
             except pytz.UnknownTimeZoneError:
                 die(True, "The specified timezone (%s) is invalid" % self.options['timezone'])
             except:
@@ -374,7 +377,10 @@
         fp.close()
 
         if is_win32:
-            import _winreg
+            try:
+                import _winreg
+            except ImportError:
+                _winreg = None
             x=_winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE)
             y = _winreg.OpenKey(x, r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", 0,_winreg.KEY_ALL_ACCESS)
             _winreg.SetValueEx(y,"PGPASSFILE", 0, _winreg.REG_EXPAND_SZ, filename )
@@ -436,16 +442,18 @@
         p = ConfigParser.ConfigParser()
         loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS.keys()))
         p.add_section('options')
-        for opt in self.options.keys():
+        for opt in sorted(self.options.keys()):
             if opt in ('version', 'language', 'translate_out', 'translate_in', 'init', 'update'):
                 continue
+            if opt in self.blacklist_for_save:
+                continue
             if opt in ('log_level', 'assert_exit_level'):
                 p.set('options', opt, loglevelnames.get(self.options[opt], self.options[opt]))
             else:
                 p.set('options', opt, self.options[opt])
 
-        for sec in self.misc.keys():
-            for opt in self.misc[sec].keys():
+        for sec in sorted(self.misc.keys()):
+            for opt in sorted(self.misc[sec].keys()):
                 p.set(sec,opt,self.misc[sec][opt])
 
         # try to create the directories and write the file

=== removed file 'bin/tools/maintenance.py'
--- bin/tools/maintenance.py	2009-10-20 10:52:23 +0000
+++ bin/tools/maintenance.py	1970-01-01 00:00:00 +0000
@@ -1,69 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#    
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
-#
-##############################################################################
-
-import xmlrpclib
-
-class RemoteContractException(Exception): pass
-
-class remote_contract(object):
-    def __init__(self, contract_id, contract_password, modules=None):
-        self.__server = 'http://tiny.my.odoo.com:8069/xmlrpc/'
-        self.__db = "tiny_belgium"
-        self.__password = "maintenance"
-        self.__login = "maintenance"
-        
-        rpc = xmlrpclib.ServerProxy(self.__server + 'common')
-        try:
-            self.__userid = rpc.login(self.__db, self.__login, self.__password)
-        except:
-            raise RemoteContractException("Unable to contact the migration server")
-
-        if not self.__userid:
-            raise RemoteContractException("Unable to contact the migration server")
-
-        self.__rpc = xmlrpclib.ServerProxy(self.__server + 'object')
-        
-
-        contract = {
-            'name': contract_id,
-            'password': contract_password,
-        }
-        if modules is None:
-            modules = []
-
-        info = self.check_contract(modules, contract)
-        for n in info:
-            setattr(self, n, info[n])
-        
-        self.name = contract_id
-        self.contract_id = self.name
-        self.password = contract_password
-        
-    def __getattr__(self, fun):
-        def remote_call(*args, **kwargs):
-            return self.__rpc.execute(self.__db, self.__userid, self.__password, 'maintenance.maintenance', fun, *args, **kwargs)
-        return remote_call
-
-    def __getitem__(self, item):
-        return getattr(self, item)
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-


Follow ups