Odoo中文社区可以通过以下三个域名访问:shine-it.net , odoocn.org,odoo.net.cn

原论坛用户的基本信息和发帖这里都予以保留,请注意:原论坛用户无需重新注册新用户,但是您的密码需要重置

开发人员可以登录gitter讨论组: http://gitter.im/odoo-china/Talk, 需要github账号

如果您登录系统碰到问题,请在微信公众号留言:

OPENERP 库存管理源码分析(目前是库链分析)



  • 既然是源码 就先开门见 "米田共" 吧 stock.py 模块的类列表[img]www.shine-it.net/attachments/month_1003/20100309_4cecc7f05dab5ad97937BUadDdZKL7It.jpg[/img]
    1.1

    stock.location
    [color=Blue] 'chained_location_id': fields.many2one('stock.location', 'Chained Location If Fixed'),[/color]
    [color=Blue] 'chained_location_type': fields.selection([('none', 'None'), ('customer', 'Customer'), ('fixed', 'Fixed Location')],[/color]
    [color=Blue] 'Chained Location Type', required=True),[/color]
    [color=Blue] 'chained_auto_packing': fields.selection([/color]
    [color=Blue] [('auto', 'Automatic Move'), ('manual', 'Manual Operation'), ('transparent', 'Automatic No Step Added')],[/color]
    [color=Blue] 'Automatic Move',[/color]
    [color=Blue] required=True,[/color]
    [color=Blue] help="This is used only if you selected a chained location type.n" [/color]
    [color=Blue] "The 'Automatic Move' value will create a stock move after the current one that will be "[/color]
    [color=Blue] "validated automatically. With 'Manual Operation', the stock move has to be validated "[/color]
    [color=Blue] "by a worker. With 'Automatic No Step Added', the location is replaced in the original move."[/color]
    [color=Blue] ),[/color]
    库位的库链概念

    从下面这个源码上看
    

    [color=DarkOrange] def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}):[/color]
    [color=DarkOrange] result = None[/color]
    [color=DarkOrange] if location.chained_location_type == 'customer':[/color]
    [color=DarkOrange] if partner:[/color]
    [color=DarkOrange] result = partner.property_stock_customer[/color]
    [color=DarkOrange] elif location.chained_location_type == 'fixed':[/color]
    [color=DarkOrange] result = location.chained_location_id[/color]
    [color=DarkOrange] if result:[/color]
    [color=DarkOrange] return result, location.chained_auto_packing, location.chained_delay[/color]
    [color=DarkOrange] return result[/color]
    当 库链类型为客户的话 [color=DarkOrange]chained_location_get [/color] 将返回 业务伙伴的默认客户库位
    当 库链类型为固定的话 [color=DarkOrange]chained_location_get [/color] 将返回 chained_location_id的库位值
    还能分析出 如果选择库链类型为客户为 客户 固定连锁库位(Chained Location If Fixed) 可以不用设置
    如果选择库链类型为客户为 固定 固定连锁库位(Chained Location If Fixed) 需要设置

    stock.move

    def _chain_compute(self, cr, uid, moves, context={}):
        result = {}
        for m in moves:
            dest = self.pool.get('stock.location').[color=DarkOrange]chained_location_get[/color](
                cr,
                uid,
                [color=Red]m.location_dest_id,[/color]  #总是从 目的地库位上得到库链值
                m.picking_id and m.picking_id.address_id and m.picking_id.address_id.partner_id,
                m.product_id,
                context
            )
            if dest:
                if dest[1] == 'transparent':
                    self.write(cr, uid, [m.id], {
                        'date_planned': (DateTime.strptime(m.date_planned, '%Y-%m-%d %H:%M:%S') + 
                            DateTime.RelativeDateTime(days=dest[2] or 0)).strftime('%Y-%m-%d'),
                        '[color=Red]location_dest_id': dest[0].id[/color]})
                else:
                    result.setdefault(m.picking_id, [])
                    result[m.picking_id].append( (m, dest) )
        return result
    
    当库链计算时 在指定的出入库明细集合 moves 里 循环遍历每个出入库明细行 获得库链值 判断当库链[color=Blue]chained_auto_packing的值为[/color]transparent(透明)
    名称为[color=Blue]Automatic No Step Added(没有自动添加的步骤)[/color] 时 更新出入库明细行的计划日期+库链延迟(天) 同时最关键的是 改变 出入库明细行的出库目的地
    从而 实现 透明调拨  
    当库链[color=Blue]chained_auto_packing的值不是[/color]transparent(透明)时 当前函数就不处理了(还是把球踢给别人吧)返回 没有处理的出入库明细行和库链值的集合
    
    最变态的在这里***
    def action_confirm(self, cr, uid, ids, context={}):
        # ids = map(lambda m: m.id, moves)
        moves = self.browse(cr, uid, ids)
        self.write(cr, uid, ids, {'state': 'confirmed'})
        i = 0
    
        def create_chained_picking(self, cr, uid, moves, context):
            new_moves = []
            for picking, todo in self._chain_compute(cr, uid, moves, context).items():
                ptype = self.pool.get('stock.location').picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
                pickid = self.pool.get('stock.picking').create(cr, uid, {
                    'name': picking.name,
                    'origin': str(picking.origin or ''),
                    'type': ptype,
                    'note': picking.note,
                    'move_type': picking.move_type,
                  [color=Red]  'auto_picking': todo[0][1][1] == 'auto',[/color]        # 就是先获得[color=Blue]chained_auto_packing的值[/color]是不是自动[color=Red](auto:[/color][color=Blue]Automatic Move[/color][color=Red])[/color] 为真就是自动装箱
                    'address_id': picking.address_id.id,
                    'invoice_state': 'none'
                })
                for move, (loc, auto, delay) in todo:
                    # Is it smart to copy ? May be it's better to recreate ?
                    new_id = self.pool.get('stock.move').copy(cr, uid, move.id, {
                        'location_id': move.location_dest_id.id,
                        'location_dest_id': loc.id,
                        'date_moved': time.strftime('%Y-%m-%d'),
                        'picking_id': pickid,
                        'state': 'waiting',
                        'move_history_ids': [],
                        'date_planned': (DateTime.strptime(move.date_planned, '%Y-%m-%d %H:%M:%S') +
                                    DateTime.RelativeDateTime(days=delay or            0)).strftime('%Y-%m-%d'),
                        'move_history_ids2': []}
                    )
                    self.pool.get('stock.move').write(cr, uid, [move.id], {
                        'move_dest_id': new_id,
                        'move_history_ids': [(4, new_id)]
                    })
                    new_moves.append(self.browse(cr, uid, [new_id])[0])
                wf_service = netsvc.LocalService("workflow")
                wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
            if new_moves:
                create_chained_picking(self, cr, uid, new_moves, context)
        create_chained_picking(self, cr, uid, moves, context)
        return []
    
       计算库链函数_chain_compute  只能完成库链处理的最简单的处理(就是打打酱油) 变态复杂的处理还得交给他大哥 create_chained_picking(建立库链出库单或入库单/建立库链装箱单)处理同时没那么简单还要被大哥不停的使唤 ()
       这位大哥只有在 stock.move-action_confirm触发时才会执行 话说这位大哥函数 处事原则是赶尽杀绝(递归大法) 
    

    老板action_confirm给了个名单(库链处理明细) , create_chained_picking大哥先让_chain_compute小弟把里面简单做掉的处理了再把复杂的名单交给大哥亲自处理 ,大哥处理了之后 把处理掉的名单再次交给小弟让它找到被大哥处理掉的名单上能给他们报仇的人的名单 然后先处理掉名单上简单的 再把复杂的再交给大哥亲自处理 直到赶紧杀绝为止!
    新生成的出入库单(装箱单)的[color=Red]auto_picking 就要看库链的自动调拨的值了
    [/color]
    举个例子 设定几个库位 C1, K1, K2, K3,K4,K5
    K1 的 库链类型为固定 ,库链库位为K2(K1死掉了K2会给它报仇的), 自动调拨([color=Blue]Automatic Move[/color]):
    为 [color=Blue]'auto', 'Automatic Move'[/color]
    K2 的 库链类型为客户(和固定处理方式一样,库链库位在库位信息里不用设置,会从出入库单的客户上的默认客户库位上获取假定为K3)
    1 当一个出库单是从C1到K1时 当确认(confirm)操作时 自动生成一个从K1到K2的出库单 同时原来的出库单明细行上的 ('move_dest_id': new_id,
    'move_history_ids': [(4, new_id)] )移动目标值为从K1到K2的出库单对应的明细行的值
    move_history_ids 对应 数据库表 stock_move_history_ids 这个表的作用到这里也就基本清楚了

                           K4 的 库链类型为客户  自动调拨([color=Blue]Automatic Move[/color]):                                
    

    为 [color=Blue]'transparent', 'Automatic No Step Added'[/color] ,库链库位为K5
    2 当一个出库单是从C1到K4是 当出入库单的action_confirm触发时 (出入库单的action_confirm 方法会调用 出入库明细的action_confirm)
    出入库明细的出库目的地就会从 K4变成K5 .没有新添加什么步骤 可能就是所谓透明

    [[i] 本帖最后由 leetaizhu 于 2010-3-10 17:46 编辑 [/i]]



  • 既然是源码 就先开门见 "米田共" 吧 stock.py 模块的类列表[img]www.shine-it.net/attachments/month_1003/20100309_4cecc7f05dab5ad97937BUadDdZKL7It.jpg[/img]
    1.1

    stock.location
    [color=Blue] 'chained_location_id': fields.many2one('stock.location', 'Chained Location If Fixed'),[/color]
    [color=Blue] 'chained_location_type': fields.selection([('none', 'None'), ('customer', 'Customer'), ('fixed', 'Fixed Location')],[/color]
    [color=Blue] 'Chained Location Type', required=True),[/color]
    [color=Blue] 'chained_auto_packing': fields.selection([/color]
    [color=Blue] [('auto', 'Automatic Move'), ('manual', 'Manual Operation'), ('transparent', 'Automatic No Step Added')],[/color]
    [color=Blue] 'Automatic Move',[/color]
    [color=Blue] required=True,[/color]
    [color=Blue] help="This is used only if you selected a chained location type.n" [/color]
    [color=Blue] "The 'Automatic Move' value will create a stock move after the current one that will be "[/color]
    [color=Blue] "validated automatically. With 'Manual Operation', the stock move has to be validated "[/color]
    [color=Blue] "by a worker. With 'Automatic No Step Added', the location is replaced in the original move."[/color]
    [color=Blue] ),[/color]
    库位的库链概念

    从下面这个源码上看
    

    [color=DarkOrange] def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}):[/color]
    [color=DarkOrange] result = None[/color]
    [color=DarkOrange] if location.chained_location_type == 'customer':[/color]
    [color=DarkOrange] if partner:[/color]
    [color=DarkOrange] result = partner.property_stock_customer[/color]
    [color=DarkOrange] elif location.chained_location_type == 'fixed':[/color]
    [color=DarkOrange] result = location.chained_location_id[/color]
    [color=DarkOrange] if result:[/color]
    [color=DarkOrange] return result, location.chained_auto_packing, location.chained_delay[/color]
    [color=DarkOrange] return result[/color]
    当 库链类型为客户的话 [color=DarkOrange]chained_location_get [/color] 将返回 业务伙伴的默认客户库位
    当 库链类型为固定的话 [color=DarkOrange]chained_location_get [/color] 将返回 chained_location_id的库位值
    还能分析出 如果选择库链类型为客户为 客户 固定连锁库位(Chained Location If Fixed) 可以不用设置
    如果选择库链类型为客户为 固定 固定连锁库位(Chained Location If Fixed) 需要设置

    stock.move

    def _chain_compute(self, cr, uid, moves, context={}):
        result = {}
        for m in moves:
            dest = self.pool.get('stock.location').[color=DarkOrange]chained_location_get[/color](
                cr,
                uid,
                [color=Red]m.location_dest_id,[/color]  #总是从 目的地库位上得到库链值
                m.picking_id and m.picking_id.address_id and m.picking_id.address_id.partner_id,
                m.product_id,
                context
            )
            if dest:
                if dest[1] == 'transparent':
                    self.write(cr, uid, [m.id], {
                        'date_planned': (DateTime.strptime(m.date_planned, '%Y-%m-%d %H:%M:%S') + 
                            DateTime.RelativeDateTime(days=dest[2] or 0)).strftime('%Y-%m-%d'),
                        '[color=Red]location_dest_id': dest[0].id[/color]})
                else:
                    result.setdefault(m.picking_id, [])
                    result[m.picking_id].append( (m, dest) )
        return result
    
    当库链计算时 在指定的出入库明细集合 moves 里 循环遍历每个出入库明细行 获得库链值 判断当库链[color=Blue]chained_auto_packing的值为[/color]transparent(透明)
    名称为[color=Blue]Automatic No Step Added(没有自动添加的步骤)[/color] 时 更新出入库明细行的计划日期+库链延迟(天) 同时最关键的是 改变 出入库明细行的出库目的地
    从而 实现 透明调拨  
    当库链[color=Blue]chained_auto_packing的值不是[/color]transparent(透明)时 当前函数就不处理了(还是把球踢给别人吧)返回 没有处理的出入库明细行和库链值的集合
    
    最变态的在这里***
    def action_confirm(self, cr, uid, ids, context={}):
        # ids = map(lambda m: m.id, moves)
        moves = self.browse(cr, uid, ids)
        self.write(cr, uid, ids, {'state': 'confirmed'})
        i = 0
    
        def create_chained_picking(self, cr, uid, moves, context):
            new_moves = []
            for picking, todo in self._chain_compute(cr, uid, moves, context).items():
                ptype = self.pool.get('stock.location').picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
                pickid = self.pool.get('stock.picking').create(cr, uid, {
                    'name': picking.name,
                    'origin': str(picking.origin or ''),
                    'type': ptype,
                    'note': picking.note,
                    'move_type': picking.move_type,
                  [color=Red]  'auto_picking': todo[0][1][1] == 'auto',[/color]        # 就是先获得[color=Blue]chained_auto_packing的值[/color]是不是自动[color=Red](auto:[/color][color=Blue]Automatic Move[/color][color=Red])[/color] 为真就是自动装箱
                    'address_id': picking.address_id.id,
                    'invoice_state': 'none'
                })
                for move, (loc, auto, delay) in todo:
                    # Is it smart to copy ? May be it's better to recreate ?
                    new_id = self.pool.get('stock.move').copy(cr, uid, move.id, {
                        'location_id': move.location_dest_id.id,
                        'location_dest_id': loc.id,
                        'date_moved': time.strftime('%Y-%m-%d'),
                        'picking_id': pickid,
                        'state': 'waiting',
                        'move_history_ids': [],
                        'date_planned': (DateTime.strptime(move.date_planned, '%Y-%m-%d %H:%M:%S') +
                                    DateTime.RelativeDateTime(days=delay or            0)).strftime('%Y-%m-%d'),
                        'move_history_ids2': []}
                    )
                    self.pool.get('stock.move').write(cr, uid, [move.id], {
                        'move_dest_id': new_id,
                        'move_history_ids': [(4, new_id)]
                    })
                    new_moves.append(self.browse(cr, uid, [new_id])[0])
                wf_service = netsvc.LocalService("workflow")
                wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
            if new_moves:
                create_chained_picking(self, cr, uid, new_moves, context)
        create_chained_picking(self, cr, uid, moves, context)
        return []
    
       计算库链函数_chain_compute  只能完成库链处理的最简单的处理(就是打打酱油) 变态复杂的处理还得交给他大哥 create_chained_picking(建立库链出库单或入库单/建立库链装箱单)处理同时没那么简单还要被大哥不停的使唤 ()
       这位大哥只有在 stock.move-action_confirm触发时才会执行 话说这位大哥函数 处事原则是赶尽杀绝(递归大法) 
    

    老板action_confirm给了个名单(库链处理明细) , create_chained_picking大哥先让_chain_compute小弟把里面简单做掉的处理了再把复杂的名单交给大哥亲自处理 ,大哥处理了之后 把处理掉的名单再次交给小弟让它找到被大哥处理掉的名单上能给他们报仇的人的名单 然后先处理掉名单上简单的 再把复杂的再交给大哥亲自处理 直到赶紧杀绝为止!
    新生成的出入库单(装箱单)的[color=Red]auto_picking 就要看库链的自动调拨的值了
    [/color]
    举个例子 设定几个库位 C1, K1, K2, K3,K4,K5
    K1 的 库链类型为固定 ,库链库位为K2(K1死掉了K2会给它报仇的), 自动调拨([color=Blue]Automatic Move[/color]):
    为 [color=Blue]'auto', 'Automatic Move'[/color]
    K2 的 库链类型为客户(和固定处理方式一样,库链库位在库位信息里不用设置,会从出入库单的客户上的默认客户库位上获取假定为K3)
    1 当一个出库单是从C1到K1时 当确认(confirm)操作时 自动生成一个从K1到K2的出库单 同时原来的出库单明细行上的 ('move_dest_id': new_id,
    'move_history_ids': [(4, new_id)] )移动目标值为从K1到K2的出库单对应的明细行的值
    move_history_ids 对应 数据库表 stock_move_history_ids 这个表的作用到这里也就基本清楚了

                           K4 的 库链类型为客户  自动调拨([color=Blue]Automatic Move[/color]):                                
    

    为 [color=Blue]'transparent', 'Automatic No Step Added'[/color] ,库链库位为K5
    2 当一个出库单是从C1到K4是 当出入库单的action_confirm触发时 (出入库单的action_confirm 方法会调用 出入库明细的action_confirm)
    出入库明细的出库目的地就会从 K4变成K5 .没有新添加什么步骤 可能就是所谓透明

    [[i] 本帖最后由 leetaizhu 于 2010-3-10 17:46 编辑 [/i]]


  • 管理员

    开源软件就应该这样去解剖,楼主继续。


  • 管理员

    支持lz:handshake



  • 你这不是给幼儿园读格林童话吗



  • 楼主好认真了。我其实也作了一些这部分工作,但是没有整理发贴。看到楼主的积极性,让我感动!:lol



  • 大家多发一些这样的东西,对学习openerp是非常有益的。希望能参与进来。



  • 赞一个!!



  • mark


登录后回复
 

与 Odoo 中文社区 的连接断开,我们正在尝试重连,请耐心等待