odoo销售流程代码简单剖析
来源:互联网 发布:java读取文件Textfile 编辑:程序博客网 时间:2024/05/01 08:39
odoo开发技术交流群【73934270】
1、新建销售报价单
2、点击确认订单,将报价单转为销售订单,同时生成对应出库单,相关代码:
确定按钮执行的方法为 sale.order 的 action_button_confirm 方法,具体代码:
def action_button_confirm(self, cr, uid, ids, context=None): if not context: context = {} assert len(ids) == 1, 'This option should only be used for a single id at a time.' self.signal_workflow(cr, uid, ids, 'order_confirm') if context.get('send_email'): self.force_quotation_send(cr, uid, ids, context=context) return True可以看到代码有触发工作流,来确认销售订单;借住工作流视图
我们是从 draft 执行 order_confirm 进入router,此处我们打开看到,执行了 sale.order 类的 action_wait 方法,具体代码:
def action_wait(self, cr, uid, ids, context=None):#只处理自身的销售订单和产品清单的信息更新 context = context or {} for o in self.browse(cr, uid, ids): if not any(line.state != 'cancel' for line in o.order_line): raise osv.except_osv(_('Error!'),_('You cannot confirm a sales order which has no line.')) noprod = self.test_no_product(cr, uid, o, context) if (o.order_policy == 'manual') or noprod: self.write(cr, uid, [o.id], {'state': 'manual', 'date_confirm': fields.date.context_today(self, cr, uid, context=context)}) else: self.write(cr, uid, [o.id], {'state': 'progress', 'date_confirm': fields.date.context_today(self, cr, uid, context=context)}) self.pool.get('sale.order.line').button_confirm(cr, uid, [x.id for x in o.order_line if x.state != 'cancel']) return True代码逻辑很清晰,不做进一步分析,进入 router 之后,发票部分我们暂时忽略;我们来看 wait_ship 部分,通过 sale.order 类的 procurement_needed 方法的返回值来确认程序的继续走向,具体代码:
def procurement_needed(self, cr, uid, ids, context=None): #when sale is installed only, there is no need to create procurements, that's only #further installed modules (sale_service, sale_stock) that will change this. sale_line_obj = self.pool.get('sale.order.line') res = [] for order in self.browse(cr, uid, ids, context=context): res.append(sale_line_obj.need_procurement(cr, uid, [line.id for line in order.order_line if line.state != 'cancel'], context=context)) return any(res)作者在测试的时候,上面的方法的返回值是True,工作流走到了 ship ,此处工作流执行的方法是 sale.order 类的 action_ship_create 方法,代码:
def action_ship_create(self, cr, uid, ids, context=None): """Create the required procurements to supply sales order lines, also connecting the procurements to appropriate stock moves in order to bring the goods to the sales order's requested location. :return: True """ context = context or {} context['lang'] = self.pool['res.users'].browse(cr, uid, uid).lang procurement_obj = self.pool.get('procurement.order') sale_line_obj = self.pool.get('sale.order.line') for order in self.browse(cr, uid, ids, context=context): proc_ids = [] vals = self._prepare_procurement_group(cr, uid, order, context=context) if not order.procurement_group_id: group_id = self.pool.get("procurement.group").create(cr, uid, vals, context=context) order.write({'procurement_group_id': group_id}) for line in order.order_line: if line.state == 'cancel': continue #Try to fix exception procurement (possible when after a shipping exception the user choose to recreate) if line.procurement_ids: #first check them to see if they are in exception or not (one of the related moves is cancelled) procurement_obj.check(cr, uid, [x.id for x in line.procurement_ids if x.state not in ['cancel', 'done']]) line.refresh() #run again procurement that are in exception in order to trigger another move except_proc_ids = [x.id for x in line.procurement_ids if x.state in ('exception', 'cancel')] procurement_obj.reset_to_confirmed(cr, uid, except_proc_ids, context=context) proc_ids += except_proc_ids elif sale_line_obj.need_procurement(cr, uid, [line.id], context=context): if (line.state == 'done') or not line.product_id: continue vals = self._prepare_order_line_procurement(cr, uid, order, line, group_id=order.procurement_group_id.id, context=context) ctx = context.copy() ctx['procurement_autorun_defer'] = True proc_id = procurement_obj.create(cr, uid, vals, context=ctx)#此处执行了procurement_order表记录的生成, proc_ids.append(proc_id) #Confirm procurement order such that rules will be applied on it #note that the workflow normally ensure proc_ids isn't an empty list procurement_obj.run(cr, uid, proc_ids, context=context) #此处run执行了stock_move表记录的生成等一系列操作,执行的run顺序===》addons/stock/procurement.py(line 208) #===》addons/procurement/procurement.py(line 197),stock(前者)扩展了pro(后者)的run方法 #if shipping was in exception and the user choose to recreate the delivery order, write the new status of SO if order.state == 'shipping_except': val = {'state': 'progress', '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 order.write(val) return True
上面代码生成与销售订单对应的补货记录,同时生成与销售订单对应的出库单,注意这里,在追代码的时候,procurement_obj.run 处调用,代码里只能看到相应的stock.move记录的生成,并没有对应出库单stock.picking的生成,一下代码是procurement_obj.run 调用的代码追踪:
def run(self, cr, uid, ids, autocommit=False, context=None): new_ids = [x.id for x in self.browse(cr, uid, ids, context=context) if x.state not in ('running', 'done', 'cancel')] res = super(procurement_order, self).run(cr, uid, new_ids, autocommit=autocommit, context=context) #after all the procurements are run, check if some created a draft stock move that needs to be confirmed #(we do that in batch because it fasts the picking assignation and the picking state computation) move_to_confirm_ids = [] for procurement in self.browse(cr, uid, new_ids, context=context): if procurement.state == "running" and procurement.rule_id and procurement.rule_id.action == "move": move_to_confirm_ids += [m.id for m in procurement.move_ids if m.state == 'draft'] if move_to_confirm_ids: self.pool.get('stock.move').action_confirm(cr, uid, move_to_confirm_ids, context=context) return res上面为stock模块扩展的run方法,super部分调用到父类 run 方法, 此处代码标记为1代
def run(self, cr, uid, ids, autocommit=False, context=None):#主要是变更procurement_order表的信息 for procurement_id in ids: #we intentionnaly do the browse under the for loop to avoid caching all ids which would be resource greedy #and useless as we'll make a refresh later that will invalidate all the cache (and thus the next iteration #will fetch all the ids again) procurement = self.browse(cr, uid, procurement_id, context=context) if procurement.state not in ("running", "done"): try: if self._assign(cr, uid, procurement, context=context): res = self._run(cr, uid, procurement, context=context or {}) #上一条 _run先调用了addons/stock/procurement.py(line 196)_run方法,生成stock_move记录 if res: self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context) else: self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) else: self.message_post(cr, uid, [procurement.id], body=_('No rule matching this procurement'), context=context) self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context) if autocommit: cr.commit() except OperationalError: if autocommit: cr.rollback() continue else: raise return True上面代码备注的中文部分,_run 方法代码,调用到stock模块中扩展的_run(下面代码),上面代码标记为2代
def _run(self, cr, uid, procurement, context=None): #生成stock_move表记录 if procurement.rule_id and procurement.rule_id.action == 'move': if not procurement.rule_id.location_src_id: self.message_post(cr, uid, [procurement.id], body=_('No source location defined!'), context=context) return False move_obj = self.pool.get('stock.move') move_dict = self._run_move_create(cr, uid, procurement, context=context) #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) move_obj.create(cr, SUPERUSER_ID, move_dict, context=context) return True return super(procurement_order, self)._run(cr, uid, procurement, context=context)上面代码编辑为3代,流程分析:1代中res = super 跳入2代里执行,2代res = self._run(具体执行代码在3代里)部分执行的结果生成销售订单对应的stock.move记录,然后返回到2代再返回到1代,1代里继续执行,此处即是注意点,注意代码self.pool.get('stock.move').action_confirm,此处代码跳转到stock.move类中,picking 的生成即在stock.move 的 confirm 方法中实现的,剩下代码不做进一步详解,如有兴趣,可留言与我一起讨论分析
*以上分析为本人在学习odoo过程中的一些学习记录,如有错误请斧正,以免误导其他odoo学者
2 0
- odoo销售流程代码简单剖析
- odoo 销售订单出库单操作代码简单剖析
- odoo采购单代码剖析
- odoo采购单入库代码剖析
- odoo 执行流程
- Odoo 运行流程
- Odoo进销存(采购、销售、仓库)入门教程 - 上
- Odoo进销存(采购、销售、仓库)入门教程 - 下
- 销售必知:销售流程
- 销售流程杂谈
- 房地产销售流程详细
- 销售Invoice管理流程
- 网络专业化销售流程
- 如何制定销售流程
- RetargetAction实现原理简单代码剖析
- QEMU live migration代码简单剖析
- WPF剖析最简单的XAML代码
- Odoo
- 栈帧
- typedef 函数指针
- C 指针&&数组
- C 指针&&函数
- C 指针&&表达式&&常量
- odoo销售流程代码简单剖析
- 发布项目到JCenter中遇到的问题
- 为什么 没有缺省构造函数的类类型成员 必需要在初始化列表 里初始化 ?
- 深度探索C++关键字之 virtual
- 【转载】Sublime Text 3 插件的汉化、开发、发布方法教程(赵亮-碧海情天-theforevr)
- 参加会议(面向对象)
- nginx中conf配置
- 让页面不允许iframe嵌入,更加安全
- javaIO流