[REF] sale: totally reworked the action_ship_create modularization:
authorRaphaël Valyi <rvalyi@gmail.com>
Sun, 2 Oct 2011 17:39:52 +0000 (14:39 -0300)
committerRaphaël Valyi <rvalyi@gmail.com>
Sun, 2 Oct 2011 17:39:52 +0000 (14:39 -0300)
- action_ship_create now calls into a a method allowing to partition the picking
- picking, moves and procurements can be customized BEFORE they are created into the database
- there is no empty method
- I commented in the shipment exception management as it looks buggy. I just reproduced the original code however

bzr revid: rvalyi@gmail.com-20111002173952-xlcmt6u1pgj6k9k4

addons/sale/sale.py

index fc70218..3e7e58c 100644 (file)
@@ -673,135 +673,127 @@ class sale_order(osv.osv):
                 return False
             return canceled
 
-    def _get_order_picking_key(self, cr, uid, order, order_data, order_line, pickings_dict, context=None):
-        """Allows to partition a sale over several pickings: just override it and return
-           a unique key for the given parameters. If key changes, a new picking will be created.
-           :params order: the sale order
-           :params order_data: a place holder to store data while iterating the order lines
-           :params line: the sale order line
-           :params pickings_dict: the current dictionary of key / picking_id for this order
-           :return: unique key for those parameters
-           :rtype: string
-        """
-        return "default"
-
-    def _create_order_picking(self, cr, uid, order, order_data, line, picking_dict, picking_vals, context=None):
-        picking_vals['name'] = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
-        return self.pool.get('stock.picking').create(cr, uid, picking_vals)
-
-    def _create_line_move(self, cr, uid, order, order_data, line, move_vals, context=None):
-        return self.pool.get('stock.move').create(cr, uid, move_vals)
-
-    def _create_line_procurement(self, cr, uid, order, order_data, line, move_id, proc_vals, context=None):
-        return self.pool.get('procurement.order').create(cr, uid, proc_vals)
 
-    def action_ship_create(self, cr, uid, ids, *args):
-        wf_service = netsvc.LocalService("workflow")
-        move_obj = self.pool.get('stock.move')
-        proc_obj = self.pool.get('procurement.order')
-        for order in self.browse(cr, uid, ids, context={}):
-            output_id = order.shop_id.warehouse_id.lot_output_id.id
-            proc_ids = []
-            pickings = {}
-            order_data = {} #a place holder to store data while iteraing the lines if needed
+    def _prepare_proc(self, cr, uid, order, line, move_id, date_planned, *args):
+        return {
+            'name': line.name,
+            'origin': order.name,
+            'date_planned': date_planned,
+            'product_id': line.product_id.id,
+            'product_qty': line.product_uom_qty,
+            'product_uom': line.product_uom.id,
+            'product_uos_qty': (line.product_uos and line.product_uos_qty)\
+                    or line.product_uom_qty,
+            'product_uos': (line.product_uos and line.product_uos.id)\
+                    or line.product_uom.id,
+            'location_id': order.shop_id.warehouse_id.lot_stock_id.id,
+            'procure_method': line.type,
+            'move_id': move_id,
+            'property_ids': [(6, 0, [x.id for x in line.property_ids])],
+            'company_id': order.company_id.id,
+            'sale_line_id': line.id,
+        }
 
-            for line in order.order_line:
-                date_planned = datetime.strptime(order.date_order, '%Y-%m-%d') + relativedelta(days=line.delay or 0.0)
-                date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
 
-                if line.state == 'done':
-                    continue
-                move_id = False
-                if line.product_id and line.product_id.product_tmpl_id.type in ('product', 'consu'):
-                    location_id = order.shop_id.warehouse_id.lot_stock_id.id
-                    picking_key = self._get_order_picking_key(cr, uid, order, order_data, line, pickings, *args)
-                    picking_id = pickings.get(picking_key, False)
+    def _prepare_move(self, cr, uid, order, line, picking_id, date_planned, *args):
+        location_id = order.shop_id.warehouse_id.lot_stock_id.id
+        output_id = order.shop_id.warehouse_id.lot_output_id.id
+        return {
+            'name': line.name[:64],
+            'picking_id': picking_id,
+            'product_id': line.product_id.id,
+            'date': date_planned,
+            'date_expected': date_planned,
+            'product_qty': line.product_uom_qty,
+            'product_uom': line.product_uom.id,
+            'product_uos_qty': line.product_uos_qty,
+            'product_uos': (line.product_uos and line.product_uos.id)\
+                    or line.product_uom.id,
+            'product_packaging': line.product_packaging.id,
+            'address_id': line.address_allotment_id.id or order.partner_shipping_id.id,
+            'location_id': location_id,
+            'location_dest_id': output_id,
+            'sale_line_id': line.id,
+            'tracking_id': False,
+            'state': 'draft',
+            #'state': 'waiting',
+            'note': line.notes,
+            'company_id': order.company_id.id,
+            'price_unit': line.product_id.standard_price or 0.0
+        }
+
+
+
+    def _prepare_picking(self, cr, uid, order, *args):
+        pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
+        return {
+            'name': pick_name,
+            'origin': order.name,
+            'type': 'out',
+            'state': 'auto',
+            'move_type': order.picking_policy,
+            'sale_id': order.id,
+            'address_id': order.partner_shipping_id.id,
+            'note': order.note,
+            'invoice_state': (order.order_policy=='picking' and '2binvoiced') or 'none',
+            'company_id': order.company_id.id,
+        }
+
+
+    def _create_pickings_an_procurements(self, cr, uid, order, order_lines, picking_id=False, *args):
+        proc_ids = []
+        for line in order_lines:
+            if line.state == 'done':
+                continue
+
+            date_planned = datetime.strptime(order.date_order, '%Y-%m-%d') + relativedelta(days=line.delay or 0.0)
+            date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
+                
+            if line.product_id:
+                if line.product_id.product_tmpl_id.type in ('product', 'consu'):
                     if not picking_id:
-                        picking_id = self._create_order_picking(cr, uid, order, order_data, line, pickings, {
-                        'origin': order.name,
-                        'type': 'out',
-                        'state': 'auto',
-                        'move_type': order.picking_policy,
-                        'sale_id': order.id,
-                        'address_id': order.partner_shipping_id.id,
-                        'note': order.note,
-                        'invoice_state': (order.order_policy=='picking' and '2binvoiced') or 'none',
-                        'company_id': order.company_id.id,
-                        }, *args)
-                        pickings[picking_key] = picking_id
-                        
-                    move_id = self._create_line_move(cr, uid, order, order_data, line, {
-                        'name': line.name[:64],
-                        'picking_id': picking_id,
-                        'product_id': line.product_id.id,
-                        'date': date_planned,
-                        'date_expected': date_planned,
-                        'product_qty': line.product_uom_qty,
-                        'product_uom': line.product_uom.id,
-                        'product_uos_qty': line.product_uos_qty,
-                        'product_uos': (line.product_uos and line.product_uos.id)\
-                                or line.product_uom.id,
-                        'product_packaging': line.product_packaging.id,
-                        'address_id': line.address_allotment_id.id or order.partner_shipping_id.id,
-                        'location_id': location_id,
-                        'location_dest_id': output_id,
-                        'sale_line_id': line.id,
-                        'tracking_id': False,
-                        'state': 'draft',
-                        'note': line.notes,
-                        'company_id': order.company_id.id,
-                        'price_unit': line.product_id.standard_price or 0.0
-                    }, *args)
-                    
-                if line.product_id:
-                    proc_id = self._create_line_procurement(cr, uid, order, order_data, line, move_id, {
-                        'name': line.name,
-                        'origin': order.name,
-                        'date_planned': date_planned,
-                        'product_id': line.product_id.id,
-                        'product_qty': line.product_uom_qty,
-                        'product_uom': line.product_uom.id,
-                        'product_uos_qty': (line.product_uos and line.product_uos_qty)\
-                                or line.product_uom_qty,
-                        'product_uos': (line.product_uos and line.product_uos.id)\
-                                or line.product_uom.id,
-                        'location_id': order.shop_id.warehouse_id.lot_stock_id.id,
-                        'procure_method': line.type,
-                        'move_id': move_id,
-                        'property_ids': [(6, 0, [x.id for x in line.property_ids])],
-                        'company_id': order.company_id.id,
-                        'sale_line_id': line.id,
-                    }, *args)
-                    proc_ids.append(proc_id)
-                    self.pool.get('sale.order.line').write(cr, uid, [line.id], {'procurement_id': proc_id})
-                    if order.state == 'shipping_except':
-                        for pick in order.picking_ids:
-                            for move in pick.move_lines:
-                                if move.state == 'cancel':
-                                    mov_ids = move_obj.search(cr, uid, [('state', '=', 'cancel'),('sale_line_id', '=', line.id),('picking_id', '=', pick.id)])
-                                    if mov_ids:
-                                        for mov in move_obj.browse(cr, uid, mov_ids):
-                                            move_obj.write(cr, uid, [move_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
-                                            proc_obj.write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
-
-            val = {}
-
-            for k, picking_id in pickings.items():
-                wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
-
-            for proc_id in proc_ids:
-                wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
+                        picking_id = self.pool.get('stock.picking').create(cr, uid, self._prepare_picking(cr, uid, order, args))
+                    move_id = self.pool.get('stock.move').create(cr, uid, self._prepare_move(cr, uid, order, line, picking_id, date_planned, args))
+                else: #a service has no stock move
+                    move_id = False
+
+                proc_id = self.pool.get('procurement.order').create(cr, uid, self._prepare_proc(cr, uid, order, line, move_id, date_planned, args))
+                proc_ids.append(proc_id)
+
+                if order.state == 'shipping_except': #deals with potentially cancelled shipments FIXME seems broken, see below
+                    for pick in order.picking_ids:
+                        for move in pick.move_lines:
+                            if move.state == 'cancel':
+                                mov_ids = self.pool.get('stock.move').search(cr, uid, [('state', '=', 'cancel'),('sale_line_id', '=', line.id),('picking_id', '=', pick.id)])
+                                if mov_ids:
+                                    for mov in move_obj.browse(cr, uid, mov_ids):
+                                        #FIXME: the following seems broken: what if move_id doesn't exist? What if there are several mov_ids? Shouldn't that be a sum?
+                                        self.pool.get('stock.move').write(cr, uid, [move_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
+                                        self.pool.get('procurement.order').write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
 
-            if order.state == 'shipping_except':
-                val['state'] = 'progress'
-                val['shipped'] = False
+        wf_service = netsvc.LocalService("workflow")
+        if picking_id:
+            wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
 
-                if (order.order_policy == 'manual'):
-                    for line in order.order_line:
-                        if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
-                            val['state'] = 'manual'
-                            break
-            self.write(cr, uid, [order.id], val)
+        for proc_id in proc_ids:
+            wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
+
+        val = {}
+        if order.state == 'shipping_except':
+            val['state'] = 'progress'
+            val['shipped'] = False
+
+            if (order.order_policy == 'manual'):
+                for line in order.order_line:
+                    if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
+                        val['state'] = 'manual'
+                        break
+        self.write(cr, uid, [order.id], val)
+        return True
+
+    def action_ship_create(self, cr, uid, ids, *args):
+        for order in self.browse(cr, uid, ids, context={}):
+            self._create_pickings_an_procurements(cr, uid, order, [line for line in order.order_line], False, args)
         return True
 
     def action_ship_end(self, cr, uid, ids, context=None):