[MERGE] forward port of branch saas-3 up to 3d80dc2
authorChristophe Simonis <chs@odoo.com>
Thu, 4 Sep 2014 15:51:42 +0000 (17:51 +0200)
committerChristophe Simonis <chs@odoo.com>
Thu, 4 Sep 2014 15:51:42 +0000 (17:51 +0200)
16 files changed:
addons/account_payment/account_move_line.py
addons/base_action_rule/__openerp__.py
addons/base_action_rule/base_action_rule.py
addons/base_action_rule/base_action_rule_data.xml
addons/calendar/__openerp__.py
addons/calendar/calendar.py
addons/calendar/calendar_cron.xml [new file with mode: 0644]
addons/calendar/calendar_data.xml
addons/crm_partner_assign/crm_portal_view.xml
addons/document/static/src/js/document.js
addons/fetchmail/__openerp__.py
addons/fetchmail/fetchmail.py
addons/payment_paypal/controllers/main.py
addons/sale/sale.py
addons/web/static/src/js/views.js
openerp/addons/base/ir/ir_cron.py

index 266876d..c0d670d 100644 (file)
@@ -51,7 +51,7 @@ class account_move_line(osv.osv):
                         if bank.state in bank_type:
                             line2bank[line.id] = bank.id
                             break
-                if line.id not in line2bank and line.partner_id.bank_ids:
+                if not line2bank.get(line.id) and line.partner_id.bank_ids:
                     line2bank[line.id] = line.partner_id.bank_ids[0].id
             else:
                 raise osv.except_osv(_('Error!'), _('There is no partner defined on the entry line.'))
index 5dd4b05..d1bed2f 100644 (file)
@@ -37,9 +37,9 @@ trigger an automatic reminder email.
     'website': 'http://www.openerp.com',
     'depends': ['base', 'resource', 'mail'],
     'data': [
+        'base_action_rule_data.xml',
         'base_action_rule_view.xml',
         'security/ir.model.access.csv',
-        'base_action_rule_data.xml'
     ],
     'demo': [],
     'installable': True,
index 5189bcb..e74e719 100644 (file)
@@ -227,10 +227,20 @@ class base_action_rule(osv.osv):
                 updated = True
         return updated
 
+    def _update_cron(self, cr, uid, context=None):
+        try:
+            cron = self.pool['ir.model.data'].get_object(
+                cr, uid, 'base_action_rule', 'ir_cron_crm_action', context=context)
+        except ValueError:
+            return False
+
+        return cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')])
+
     def create(self, cr, uid, vals, context=None):
         res_id = super(base_action_rule, self).create(cr, uid, vals, context=context)
         if self._register_hook(cr, [res_id]):
             openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
+        self._update_cron(cr, uid, context=context)
         return res_id
 
     def write(self, cr, uid, ids, vals, context=None):
@@ -239,8 +249,14 @@ class base_action_rule(osv.osv):
         super(base_action_rule, self).write(cr, uid, ids, vals, context=context)
         if self._register_hook(cr, ids):
             openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
+        self._update_cron(cr, uid, context=context)
         return True
 
+    def unlink(self, cr, uid, ids, context=None):
+        res = super(base_action_rule, self).unlink(cr, uid, ids, context=context)
+        self._update_cron(cr, uid, context=context)
+        return res
+
     def onchange_model_id(self, cr, uid, ids, model_id, context=None):
         data = {'model': False, 'filter_pre_id': False, 'filter_id': False}
         if model_id:
index d4b12f5..7898855 100644 (file)
@@ -11,6 +11,7 @@
             <field eval="'base.action.rule'" name="model"/>
             <field eval="'_check'" name="function"/>
             <field eval="'(True,)'" name="args"/>
+            <field name="active" eval="False" />
         </record>
 
     </data>
index 0cae2b6..a7e947b 100644 (file)
@@ -40,6 +40,7 @@ If you need to manage your meetings, you should install the CRM module.
     'website': 'http://www.openerp.com',
     'demo': ['calendar_demo.xml'],
     'data': [
+        'calendar_cron.xml',
         'security/ir.model.access.csv',
         'security/calendar_security.xml',
         'calendar_view.xml',
index 3e51407..f25e530 100644 (file)
@@ -415,11 +415,12 @@ class calendar_alarm_manager(osv.AbstractModel):
         return res
 
     def get_next_mail(self, cr, uid, context=None):
-        cron = self.pool.get('ir.cron').search(cr, uid, [('model', 'ilike', self._name)], context=context)
-        if cron and len(cron) == 1:
-            cron = self.pool.get('ir.cron').browse(cr, uid, cron[0], context=context)
-        else:
-            _logger.exception("Cron for " + self._name + " can not be identified !")
+        try:
+            cron = self.pool['ir.model.data'].get_object(
+                cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context)
+        except ValueError:
+            _logger.error("Cron for " + self._name + " can not be identified !")
+            return False
 
         if cron.interval_type == "weeks":
             cron_interval = cron.interval_number * 7 * 24 * 60 * 60
@@ -431,9 +432,12 @@ class calendar_alarm_manager(osv.AbstractModel):
             cron_interval = cron.interval_number * 60
         elif cron.interval_type == "seconds":
             cron_interval = cron.interval_number
+        else:
+            cron_interval = False
 
         if not cron_interval:
-            _logger.exception("Cron delay can not be computed !")
+            _logger.error("Cron delay can not be computed !")
+            return False
 
         all_events = self.get_next_potential_limit_alarm(cr, uid, cron_interval, notif=False, context=context)
 
@@ -558,6 +562,35 @@ class calendar_alarm(osv.Model):
         'interval': 'hours',
     }
 
+    def _update_cron(self, cr, uid, context=None):
+        try:
+            cron = self.pool['ir.model.data'].get_object(
+                cr, uid, 'calendar', 'ir_cron_scheduler_alarm', context=context)
+        except ValueError:
+            return False
+        return cron.toggle(model=self._name, domain=[('type', '=', 'email')])
+
+    def create(self, cr, uid, values, context=None):
+        res = super(calendar_alarm, self).create(cr, uid, values, context=context)
+
+        self._update_cron(cr, uid, context=context)
+
+        return res
+
+    def write(self, cr, uid, ids, values, context=None):
+        res = super(calendar_alarm, self).write(cr, uid, ids, values, context=context)
+
+        self._update_cron(cr, uid, context=context)
+
+        return res
+
+    def unlink(self, cr, uid, ids, context=None):
+        res = super(calendar_alarm, self).unlink(cr, uid, ids, context=context)
+
+        self._update_cron(cr, uid, context=context)
+
+        return res
+
 
 class ir_values(osv.Model):
     _inherit = 'ir.values'
diff --git a/addons/calendar/calendar_cron.xml b/addons/calendar/calendar_cron.xml
new file mode 100644 (file)
index 0000000..313a021
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<openerp>
+    <data noupdate="1">
+        <!-- Scheduler for Event Alarm-->
+        <record forcecreate="True" id="ir_cron_scheduler_alarm" model="ir.cron">
+            <field name="name">Run Event Reminder</field>
+            <field eval="False" name="active" />
+            <field name="user_id" ref="base.user_root" />
+            <field name="interval_number">30</field>
+            <field name="interval_type">minutes</field>
+            <field name="numbercall">-1</field>
+            <field eval="False" name="doall" />
+            <field eval="'calendar.alarm_manager'" name="model" />
+            <field eval="'get_next_mail'" name="function" />
+            <!--<field eval="'(False,)'" name="args" />-->
+        </record>
+    </data>
+</openerp>
\ No newline at end of file
index 68d7aa4..e13edaf 100644 (file)
             <field name="interval">days</field>
             <field name="type">email</field>            
         </record>
-        
-
-        <!-- Scheduler for Event Alarm-->
-        <record forcecreate="True" id="ir_cron_scheduler_alarm" model="ir.cron">
-            <field name="name">Run Event Reminder</field>
-            <field eval="True" name="active" />
-            <field name="user_id" ref="base.user_root" />
-            <field name="interval_number">30</field>
-            <field name="interval_type">minutes</field>
-            <field name="numbercall">-1</field>
-            <field eval="False" name="doall" />
-            <field eval="'calendar.alarm_manager'" name="model" />
-            <field eval="'get_next_mail'" name="function" />
-            <!--<field eval="'(False,)'" name="args" />-->
-        </record>
-        
+                
         <record model="calendar.event.type" id="categ_meet1">
             <field name="name">Customer Meeting</field>
         </record>
index 1ad0659..36a4f32 100644 (file)
                       <separator string="Contact" colspan="2"/>
                       <group col="2">
                           <field name="partner_id" select="1"
-                            on_change="onchange_partner_id(partner_id, email_from)" string="Customer"
+                            string="Customer"
                             colspan="2" readonly="1"/>
                           <field name="partner_name" string="Customer Name" readonly="1"/>
                           <field domain="[('domain', '=', 'contact')]" name="title" widget="selection" readonly="1"/>
index e4bce2d..5b353d5 100644 (file)
@@ -3,8 +3,10 @@ openerp.document = function (instance) {
     instance.web.Sidebar.include({
         init : function(){
             this._super.apply(this, arguments);
-            this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), });
-            this.items['files'] = [];
+            if (this.getParent().view_type == "form"){
+                this.sections.splice(1, 0, { 'name' : 'files', 'label' : _t('Attachment(s)'), });
+                this.items['files'] = [];
+            }
         },
         on_attachments_loaded: function(attachments) {
             //to display number in name if more then one attachment which has same name.
index 84a26d5..082d53d 100644 (file)
@@ -56,8 +56,8 @@ For more specific needs, you may also assign custom-defined actions
     """,
     'website': 'http://www.openerp.com',
     'data': [
-        'fetchmail_view.xml',
         'fetchmail_data.xml',
+        'fetchmail_view.xml',
         'security/ir.model.access.csv',
         'fetchmail_installer_view.xml'
     ],
index 565996b..37a0f16 100644 (file)
@@ -251,27 +251,33 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
             server.write({'date': time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)})
         return True
 
-    def cron_update(self, cr, uid, context=None):
-        if context is None:
-            context = {}
-        if not context.get('fetchmail_cron_running'):
-            # Enabled/Disable cron based on the number of 'done' server of type pop or imap
-            ids = self.search(cr, uid, [('state','=','done'),('type','in',['pop','imap'])])
-            try:
-                cron_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fetchmail', 'ir_cron_mail_gateway_action')[1]
-                self.pool.get('ir.cron').write(cr, 1, [cron_id], {'active': bool(ids)})
-            except ValueError:
-                # Nevermind if default cron cannot be found
-                pass
+    def _update_cron(self, cr, uid, context=None):
+        if context and context.get('fetchmail_cron_running'):
+            return
+
+        try:
+            cron = self.pool['ir.model.data'].get_object(
+                cr, uid, 'fetchmail', 'ir_cron_mail_gateway_action', context=context)
+        except ValueError:
+            # Nevermind if default cron cannot be found
+            return
+
+        # Enabled/Disable cron based on the number of 'done' server of type pop or imap
+        cron.toggle(model=self._name, domain=[('state','=','done'), ('type','in',['pop','imap'])])
 
     def create(self, cr, uid, values, context=None):
         res = super(fetchmail_server, self).create(cr, uid, values, context=context)
-        self.cron_update(cr, uid, context=context)
+        self._update_cron(cr, uid, context=context)
         return res
 
     def write(self, cr, uid, ids, values, context=None):
         res = super(fetchmail_server, self).write(cr, uid, ids, values, context=context)
-        self.cron_update(cr, uid, context=context)
+        self._update_cron(cr, uid, context=context)
+        return res
+
+    def unlink(self, cr, uid, ids, context=None):
+        res = super(fetchmail_server, self).unlink(cr, uid, ids, context=context)
+        self._update_cron(cr, uid, context=context)
         return res
 
 class mail_mail(osv.osv):
index e07fa3d..94c8171 100644 (file)
@@ -24,7 +24,7 @@ class PaypalController(http.Controller):
         """ Extract the return URL from the data coming from paypal. """
         return_url = post.pop('return_url', '')
         if not return_url:
-            custom = json.loads(post.pop('custom', '{}'))
+            custom = json.loads(post.pop('custom', False) or '{}')
             return_url = custom.get('return_url', '/')
         return return_url
 
index b3f2cc6..25f3995 100644 (file)
@@ -597,22 +597,8 @@ class sale_order(osv.osv):
     def action_button_confirm(self, cr, uid, ids, context=None):
         assert len(ids) == 1, 'This option should only be used for a single id at a time.'
         self.signal_order_confirm(cr, uid, ids)
-
-        # redisplay the record as a sales order
-        view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'sale', 'view_order_form')
-        view_id = view_ref and view_ref[1] or False,
-        return {
-            'type': 'ir.actions.act_window',
-            'name': _('Sales Order'),
-            'res_model': 'sale.order',
-            'res_id': ids[0],
-            'view_type': 'form',
-            'view_mode': 'form',
-            'view_id': view_id,
-            'target': 'current',
-            'nodestroy': True,
-        }
-
+        return True
+        
     def action_wait(self, cr, uid, ids, context=None):
         context = context or {}
         for o in self.browse(cr, uid, ids):
index 53addf9..f8f2d75 100644 (file)
@@ -405,15 +405,36 @@ instance.web.ActionManager = instance.web.Widget.extend({
         }
         var widget = executor.widget();
         if (executor.action.target === 'new') {
+            var pre_dialog = this.dialog;
+            if (pre_dialog){
+                // prevent previous dialog to consider itself closed,
+                // right now, as we're opening a new one (prevents
+                // reload of original form view)
+                pre_dialog.off('closing', null, pre_dialog.on_close);
+            }
             if (this.dialog_widget && !this.dialog_widget.isDestroyed()) {
                 this.dialog_widget.destroy();
             }
+            // explicitly passing a closing action to dialog_stop() prevents
+            // it from reloading the original form view
             this.dialog_stop(executor.action);
             this.dialog = new instance.web.Dialog(this, {
                 title: executor.action.name,
                 dialogClass: executor.klass,
             });
-            this.dialog.on("closing", null, options.on_close);
+
+            // chain on_close triggers with previous dialog, if any
+            this.dialog.on_close = function(){
+                options.on_close.apply(null, arguments);
+                if (pre_dialog && pre_dialog.on_close){
+                    // no parameter passed to on_close as this will
+                    // only be called when the last dialog is truly
+                    // closing, and *should* trigger a reload of the
+                    // underlying form view (see comments above)
+                    pre_dialog.on_close();
+                }
+            };
+            this.dialog.on("closing", null, this.dialog.on_close);
             if (widget instanceof instance.web.ViewManager) {
                 _.extend(widget.flags, {
                     $buttons: this.dialog.$buttons,
@@ -426,6 +447,9 @@ instance.web.ActionManager = instance.web.Widget.extend({
             this.dialog.open();
             return initialized;
         } else  {
+            // explicitly passing a closing action to dialog_stop() prevents
+            // it from reloading the original form view - we're opening a
+            // completely new action anyway
             this.dialog_stop(executor.action);
             this.inner_action = executor.action;
             this.inner_widget = widget;
index 8f85beb..029c247 100644 (file)
@@ -294,4 +294,20 @@ class ir_cron(osv.osv):
         res = super(ir_cron, self).unlink(cr, uid, ids, context=context)
         return res
 
+    def try_write(self, cr, uid, ids, values, context=None):
+        try:
+            with cr.savepoint():
+                cr.execute("""SELECT id FROM "%s" WHERE id IN %%s FOR UPDATE NOWAIT""" % self._table,
+                           (tuple(ids),), log_exceptions=False)
+        except psycopg2.OperationalError:
+            pass
+        else:
+            return super(ir_cron, self).write(cr, uid, ids, values, context=context)
+        return False
+
+    def toggle(self, cr, uid, ids, model, domain, context=None):
+        active = bool(self.pool[model].search_count(cr, uid, domain, context=context))
+
+        return self.try_write(cr, uid, ids, {'active': active}, context=context)
+
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: