diff --git a/addons/sale/sale.py b/addons/sale/sale.py index fc702181206..3e7e58c72c6 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -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 _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, + } - 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 _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.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}) + + wf_service = netsvc.LocalService("workflow") + if picking_id: + 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) + + 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): - 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 - - 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) - 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) - - 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) + 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):