@api.multi defaction_confirm(self): if self._get_forbidden_state_confirm() & set(self.mapped('state')): raise UserError(_( 'It is not allowed to confirm an order in the following states: %s' ) % (', '.join(self._get_forbidden_state_confirm())))
for order in self.filtered(lambda order: order.partner_id notin order.message_partner_ids): order.message_subscribe([order.partner_id.id]) self.write({ 'state': 'sale', 'confirmation_date': fields.Datetime.now() }) self._action_confirm() if self.env['ir.config_parameter'].sudo().get_param('sale.auto_done_setting'): self.action_done() returnTrue
重点代码是self._action_confirm(),
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
@api.multi def_action_confirm(self): """ Implementation of additionnal mecanism of Sales Order confirmation. This method should be extended when the confirmation should generated other documents. In this method, the SO are in 'sale' state (not yet 'done'). """ if self.env.context.get('send_email'): self.force_quotation_send()
# create an analytic account if at least an expense product for order in self: if any([expense_policy notin [False, 'no'] for expense_policy in order.order_line.mapped('product_id.expense_policy')]): ifnot order.analytic_account_id: order._create_analytic_account()
returnTrue
通过代码注释,我们可以确定这是确认订单的附加机制,生成其他单据时候应拓展此方法。
####2.生成调拨单 继续跟踪代码 以下为sale_stock模块的代码:
1 2 3 4 5
@api.multi def_action_confirm(self): for order in self: order.order_line._action_launch_stock_rule() super(SaleOrder, self)._action_confirm()
@api.multi def_action_launch_stock_rule(self): """ Launch procurement group run method with required/custom fields genrated by a sale order line. procurement group will launch '_run_pull', '_run_buy' or '_run_manufacture' depending on the sale order line product rule. """ precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') errors = [] for line in self: if line.state != 'sale'ornot line.product_id.type in ('consu','product'): continue qty = line._get_qty_procurement() if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0: continue
group_id = line.order_id.procurement_group_id ifnot group_id: group_id = self.env['procurement.group'].create({ 'name': line.order_id.name, 'move_type': line.order_id.picking_policy, 'sale_id': line.order_id.id, 'partner_id': line.order_id.partner_shipping_id.id, }) line.order_id.procurement_group_id = group_id else: # In case the procurement group is already created and the order was # cancelled, we need to update certain values of the group. updated_vals = {} if group_id.partner_id != line.order_id.partner_shipping_id: updated_vals.update({'partner_id': line.order_id.partner_shipping_id.id}) if group_id.move_type != line.order_id.picking_policy: updated_vals.update({'move_type': line.order_id.picking_policy}) if updated_vals: group_id.write(updated_vals)
@api.model defrun(self, product_id, product_qty, product_uom, location_id, name, origin, values): """ Method used in a procurement case. The purpose is to supply the product passed as argument in the location also given as an argument. In order to be able to find a suitable location that provide the product it will search among stock.rule. """ values.setdefault('company_id', self.env['res.company']._company_default_get('procurement.group')) values.setdefault('priority', '1') values.setdefault('date_planned', fields.Datetime.now()) rule = self._get_rule(product_id, location_id, values) ifnot rule: raise UserError(_('No procurement rule found in location "%s" for product "%s".\n Check routes configuration.') % (location_id.display_name, product_id.display_name)) action = 'pull'if rule.action == 'pull_push'else rule.action if hasattr(rule, '_run_%s' % action): getattr(rule, '_run_%s' % action)(product_id, product_qty, product_uom, location_id, name, origin, values) else: _logger.error("The method _run_%s doesn't exist on the procument rules" % action) returnTrue
# create the move as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example) # Search if picking with move for it exists already: group_id = False if self.group_propagation_option == 'propagate': group_id = values.get('group_id', False) and values['group_id'].id elif self.group_propagation_option == 'fixed': group_id = self.group_id.id
data = self._get_stock_move_values(product_id, product_qty, product_uom, location_id, name, origin, values, group_id) # Since action_confirm launch following procurement_group we should activate it. move = self.env['stock.move'].sudo().with_context(force_company=data.get('company_id', False)).create(data) move._action_confirm() returnTrue
def_action_confirm(self, merge=True, merge_into=False): """ Confirms stock move or put it in waiting if it's linked to another move. :param: merge: According to this boolean, a newly confirmed move will be merged in another move of the same picking sharing its characteristics. """ move_create_proc = self.env['stock.move'] move_to_confirm = self.env['stock.move'] move_waiting = self.env['stock.move']
to_assign = {} for move in self: # if the move is preceeded, then it's waiting (if preceeding move is done, then action_assign has been called already and its state is already available) if move.move_orig_ids: move_waiting |= move else: if move.procure_method == 'make_to_order': move_create_proc |= move else: move_to_confirm |= move if move._should_be_assigned(): key = (move.group_id.id, move.location_id.id, move.location_dest_id.id) if key notin to_assign: to_assign[key] = self.env['stock.move'] to_assign[key] |= move
# create procurements for make to order moves for move in move_create_proc: values = move._prepare_procurement_values() origin = (move.group_id and move.group_id.name or (move.origin or move.picking_id.name or"/")) self.env['procurement.group'].run(move.product_id, move.product_uom_qty, move.product_uom, move.location_id, move.rule_id and move.rule_id.name or"/", origin, values)
# assign picking in batch for all confirmed move that share the same details for moves in to_assign.values(): moves._assign_picking() self._push_apply() if merge: return self._merge_moves(merge_into=merge_into) return self
def_assign_picking(self): """ Try to assign the moves to an existing picking that has not been reserved yet and has the same procurement group, locations and picking type (moves should already have them identical). Otherwise, create a new picking to assign them to. """ Picking = self.env['stock.picking'] for move in self: recompute = False picking = move._search_picking_for_assignation() if picking: if picking.partner_id.id != move.partner_id.id or picking.origin != move.origin: # If a picking is found, we'll append `move` to its move list and thus its # `partner_id` and `ref` field will refer to multiple records. In this # case, we chose to wipe them. picking.write({ 'partner_id': False, 'origin': False, }) else: recompute = True picking = Picking.create(move._get_new_picking_values()) move.write({'picking_id': picking.id}) move._assign_picking_post_process(new=recompute) # If this method is called in batch by a write on a one2many and # at some point had to create a picking, some next iterations could # try to find back the created picking. As we look for it by searching # on some computed fields, we have to force a recompute, else the # record won't be found. if recompute: move.recompute() returnTrue
@api.multi def_action_launch_stock_rule(self): res = super(SaleOrderLine, self)._action_launch_stock_rule() orders = list(set(x.order_id for x in self)) for order in orders: reassign = order.picking_ids.filtered(lambda x: x.state=='confirmed'or (x.state in ['waiting', 'assigned'] andnot x.printed)) if reassign: reassign.action_assign() return res