[IMP] safe_eval: do not log exceptions, when re-raising a new exception, make the...
[odoo/odoo.git] / addons / purchase / purchase.py
index 257d22f..e76bf4a 100644 (file)
@@ -22,9 +22,9 @@
 import time
 from datetime import datetime
 from dateutil.relativedelta import relativedelta
+from operator import attrgetter
 
 from openerp.osv import fields, osv
-from openerp import netsvc
 from openerp import pooler
 from openerp.tools.translate import _
 import openerp.addons.decimal_precision as dp
@@ -161,21 +161,21 @@ class purchase_order(osv.osv):
     ]
     _track = {
         'state': {
-            'purchase.mt_rfq_confirmed': lambda self, cr, uid, obj, ctx=None: obj['state']=='confirmed',
-            'purchase.mt_rfq_approved': lambda self, cr, uid, obj, ctx=None: obj['state']=='approved',
+            'purchase.mt_rfq_confirmed': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'confirmed',
+            'purchase.mt_rfq_approved': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'approved',
         },
     }
     _columns = {
         'name': fields.char('Order Reference', size=64, required=True, select=True, help="Unique number of the purchase order, computed automatically when the purchase order is created."),
         'origin': fields.char('Source Document', size=64,
-            help="Reference of the document that generated this purchase order request; a sale order or an internal procurement request."
+            help="Reference of the document that generated this purchase order request; a sales order or an internal procurement request."
         ),
         'partner_ref': fields.char('Supplier Reference', states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]}, size=64,
-            help="Reference of the sale order or quotation sent by your supplier. It's mainly used to do the matching when you receive the products as this reference is usually written on the delivery order sent by your supplier."),
+            help="Reference of the sales order or quotation sent by your supplier. It's mainly used to do the matching when you receive the products as this reference is usually written on the delivery order sent by your supplier."),
         'date_order':fields.date('Order Date', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)]}, select=True, help="Date on which this document has been created."),
         'date_approve':fields.date('Date Approved', readonly=1, select=True, help="Date on which purchase order has been approved"),
         'partner_id':fields.many2one('res.partner', 'Supplier', required=True, states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},
-            change_default=True, track_visibility=2),
+            change_default=True, track_visibility='always'),
         'dest_address_id':fields.many2one('res.partner', 'Customer Address (Direct Delivery)',
             states={'confirmed':[('readonly',True)], 'approved':[('readonly',True)],'done':[('readonly',True)]},
             help="Put an address if you want to deliver directly from the supplier to the customer. " \
@@ -209,7 +209,7 @@ class purchase_order(osv.osv):
         'amount_untaxed': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Untaxed Amount',
             store={
                 'purchase.order.line': (_get_order, None, 10),
-            }, multi="sums", help="The amount without tax", track_visibility=2),
+            }, multi="sums", help="The amount without tax", track_visibility='always'),
         'amount_tax': fields.function(_amount_all, digits_compute= dp.get_precision('Account'), string='Taxes',
             store={
                 'purchase.order.line': (_get_order, None, 10),
@@ -260,9 +260,7 @@ class purchase_order(osv.osv):
                 raise osv.except_osv(_('Invalid Action!'), _('In order to delete a purchase order, you must cancel it first.'))
 
         # automatically sending subflow.delete upon deletion
-        wf_service = netsvc.LocalService("workflow")
-        for id in unlink_ids:
-            wf_service.trg_validate(uid, 'purchase.order', id, 'purchase_cancel', cr)
+        self.signal_purchase_cancel(cr, uid, unlink_ids)
 
         return super(purchase_order, self).unlink(cr, uid, unlink_ids, context=context)
 
@@ -329,7 +327,7 @@ class purchase_order(osv.osv):
 
     def view_invoice(self, cr, uid, ids, context=None):
         '''
-        This function returns an action that display existing invoices of given sale order ids. It can either be a in a list or in a form view, if there is only one invoice to show.
+        This function returns an action that display existing invoices of given sales order ids. It can either be a in a list or in a form view, if there is only one invoice to show.
         '''
         mod_obj = self.pool.get('ir.model.data')
         wizard_obj = self.pool.get('purchase.order.line_invoice')
@@ -439,8 +437,7 @@ class purchase_order(osv.osv):
         This function prints the request for quotation and mark it as sent, so that we can see more easily the next step of the workflow
         '''
         assert len(ids) == 1, 'This option should only be used for a single id at a time'
-        wf_service = netsvc.LocalService("workflow")
-        wf_service.trg_validate(uid, 'purchase.order', ids[0], 'send_rfq', cr)
+        self.signal_send_rfq(cr, uid, ids)
         datas = {
                  'model': 'purchase.order',
                  'ids': ids,
@@ -486,11 +483,10 @@ class purchase_order(osv.osv):
         if not len(ids):
             return False
         self.write(cr, uid, ids, {'state':'draft','shipped':0})
-        wf_service = netsvc.LocalService("workflow")
         for p_id in ids:
             # Deleting the existing instance of workflow for PO
-            wf_service.trg_delete(uid, 'purchase.order', p_id, cr)
-            wf_service.trg_create(uid, 'purchase.order', p_id, cr)
+            self.delete_workflow(cr, uid, [p_id]) # TODO is it necessary to interleave the calls?
+            self.create_workflow(cr, uid, [p_id])
         return True
 
     def action_invoice_create(self, cr, uid, ids, context=None):
@@ -518,7 +514,7 @@ class purchase_order(osv.osv):
             inv_lines = []
             for po_line in order.order_line:
                 if po_line.product_id:
-                    acc_id = po_line.product_id.product_tmpl_id.property_account_expense.id
+                    acc_id = po_line.product_id.property_account_expense.id
                     if not acc_id:
                         acc_id = po_line.product_id.categ_id.property_account_expense_categ.id
                     if not acc_id:
@@ -566,31 +562,29 @@ class purchase_order(osv.osv):
     def has_stockable_product(self, cr, uid, ids, *args):
         for order in self.browse(cr, uid, ids):
             for order_line in order.order_line:
-                if order_line.product_id and order_line.product_id.product_tmpl_id.type in ('product', 'consu'):
+                if order_line.product_id and order_line.product_id.type in ('product', 'consu'):
                     return True
         return False
 
     def action_cancel(self, cr, uid, ids, context=None):
-        wf_service = netsvc.LocalService("workflow")
         for purchase in self.browse(cr, uid, ids, context=context):
             for pick in purchase.picking_ids:
                 if pick.state not in ('draft','cancel'):
                     raise osv.except_osv(
                         _('Unable to cancel this purchase order.'),
                         _('First cancel all receptions related to this purchase order.'))
-            for pick in purchase.picking_ids:
-                wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_cancel', cr)
+            self.pool.get('stock.picking') \
+                .signal_button_cancel(cr, uid, map(attrgetter('id'), purchase.picking_ids))
             for inv in purchase.invoice_ids:
                 if inv and inv.state not in ('cancel','draft'):
                     raise osv.except_osv(
                         _('Unable to cancel this purchase order.'),
                         _('You must first cancel all receptions related to this purchase order.'))
-                if inv:
-                    wf_service.trg_validate(uid, 'account.invoice', inv.id, 'invoice_cancel', cr)
+            self.pool.get('account.invoice') \
+                .signal_invoice_cancel(cr, uid, map(attrgetter('id'), purchase.invoice_ids))
         self.write(cr,uid,ids,{'state':'cancel'})
 
-        for (id, name) in self.name_get(cr, uid, ids):
-            wf_service.trg_validate(uid, 'purchase.order', id, 'purchase_cancel', cr)
+        self.signal_purchase_cancel(cr, uid, ids)
         return True
 
     def _prepare_order_picking(self, cr, uid, order, context=None):
@@ -648,11 +642,11 @@ class purchase_order(osv.osv):
                                will be added. A new picking will be created if omitted.
         :return: list of IDs of pickings used/created for the given order lines (usually just one)
         """
+        stock_picking = self.pool.get('stock.picking')
         if not picking_id:
-            picking_id = self.pool.get('stock.picking').create(cr, uid, self._prepare_order_picking(cr, uid, order, context=context))
+            picking_id = stock_picking.create(cr, uid, self._prepare_order_picking(cr, uid, order, context=context))
         todo_moves = []
         stock_move = self.pool.get('stock.move')
-        wf_service = netsvc.LocalService("workflow")
         for order_line in order_lines:
             if not order_line.product_id:
                 continue
@@ -663,7 +657,7 @@ class purchase_order(osv.osv):
                 todo_moves.append(move)
         stock_move.action_confirm(cr, uid, todo_moves)
         stock_move.force_assign(cr, uid, todo_moves)
-        wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
+        stock_picking.signal_button_confirm(cr, uid, [picking_id])
         return [picking_id]
 
     def action_picking_create(self, cr, uid, ids, context=None):
@@ -714,7 +708,6 @@ class purchase_order(osv.osv):
 
         """
         #TOFIX: merged order line should be unlink
-        wf_service = netsvc.LocalService("workflow")
         def make_key(br, fields):
             list_key = []
             for field in fields:
@@ -801,17 +794,10 @@ class purchase_order(osv.osv):
 
             # make triggers pointing to the old orders point to the new order
             for old_id in old_ids:
-                wf_service.trg_redirect(uid, 'purchase.order', old_id, neworder_id, cr)
-                wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr)
+                self.redirect_workflow(cr, uid, [(old_id, neworder_id)])
+                self.signal_purchase_cancel(cr, uid, [old_id]) # TODO Is it necessary to interleave the calls?
         return orders_info
 
-    # --------------------------------------
-    # OpenChatter methods and notifications
-    # --------------------------------------
-
-    def needaction_domain_get(self, cr, uid, ids, context=None):
-        return [('state', '=', 'draft')]
-
 
 class purchase_order_line(osv.osv):
     def _amount_line(self, cr, uid, ids, prop, arg, context=None):
@@ -1006,7 +992,7 @@ class procurement_order(osv.osv):
         '''
         user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
         for procurement in self.browse(cr, uid, ids, context=context):
-            if procurement.product_id.product_tmpl_id.supply_method <> 'buy':
+            if procurement.product_id.supply_method <> 'buy':
                 return False
         return True
 
@@ -1129,7 +1115,7 @@ class procurement_order(osv.osv):
             new_context.update({'lang': partner.lang, 'partner_id': partner_id})
 
             product = prod_obj.browse(cr, uid, procurement.product_id.id, context=new_context)
-            taxes_ids = procurement.product_id.product_tmpl_id.supplier_taxes_id
+            taxes_ids = procurement.product_id.supplier_taxes_id
             taxes = acc_pos_obj.map_tax(cr, uid, partner.property_account_position, taxes_ids)
 
             name = product.partner_ref
@@ -1160,35 +1146,27 @@ class procurement_order(osv.osv):
             }
             res[procurement.id] = self.create_procurement_purchase_order(cr, uid, procurement, po_vals, line_vals, context=new_context)
             self.write(cr, uid, [procurement.id], {'state': 'running', 'purchase_id': res[procurement.id]})
-        self.purchase_order_create_note(cr, uid, ids, context=context)
+        self.message_post(cr, uid, ids, body=_("Draft Purchase Order created"), context=context)
         return res
-    
+
     def _product_virtual_get(self, cr, uid, order_point):
         procurement = order_point.procurement_id
         if procurement and procurement.state != 'exception' and procurement.purchase_id and procurement.purchase_id.state in ('draft', 'confirmed'):
             return None
         return super(procurement_order, self)._product_virtual_get(cr, uid, order_point)
 
-    def purchase_order_create_note(self, cr, uid, ids, context=None):
-        for procurement in self.browse(cr, uid, ids, context=context):
-            body = _("Draft Purchase Order created")
-            self.message_post(cr, uid, [procurement.id], body=body, context=context)
-
-procurement_order()
 
-class mail_mail(osv.osv):
+class mail_mail(osv.Model):
     _name = 'mail.mail'
     _inherit = 'mail.mail'
 
     def _postprocess_sent_message(self, cr, uid, mail, context=None):
         if mail.model == 'purchase.order':
-            wf_service = netsvc.LocalService("workflow")
-            wf_service.trg_validate(uid, 'purchase.order', mail.res_id, 'send_rfq', cr)
+            self.pool.get('purchase.order').signal_send_rfq(cr, uid, [mail.res_id])
         return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context)
 
-mail_mail()
 
-class product_template(osv.osv):
+class product_template(osv.Model):
     _name = 'product.template'
     _inherit = 'product.template'
     _columns = {
@@ -1198,15 +1176,15 @@ class product_template(osv.osv):
         'purchase_ok': 1,
     }
 
-product_template()
 
-class mail_compose_message(osv.osv):
+class mail_compose_message(osv.Model):
     _inherit = 'mail.compose.message'
+
     def send_mail(self, cr, uid, ids, context=None):
         context = context or {}
         if context.get('default_model') == 'purchase.order' and context.get('default_res_id'):
-            wf_service = netsvc.LocalService("workflow")
-            wf_service.trg_validate(uid, 'purchase.order', context['default_res_id'], 'send_rfq', cr)
+            context = dict(context, mail_post_autofollow=True)
+            self.pool.get('purchase.order').signal_send_rfq(cr, uid, [context['default_res_id']])
         return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context)
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: