跳转至内容
  • 版块
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(Flatly)
  • 不使用皮肤
折叠

Odoo 中文社区

L

leetaizhu

@leetaizhu
关于
帖子
23
主题
11
群组
0
粉丝
0
关注
0

帖子

最新 最佳 有争议的

  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    Sometimes you need to refer the relation of a relation. For example, supposing you have objects: City <- State <- Country, and you need to refer Country in a City, you can define a field as below in the City object:
    'country_id': fields.related('state_id', 'country_id', type="many2one",
    relation="module.country",
    string="Country", store=False)
    就是当 City <- State <- Country
    就是想从孙子找爷爷的时候 用 related 哈哈哈


  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    产品链接装箱单的功能 用 温州-老梅 用 related属性 实现很简单

    下面是用 Functional Field 实现 产品链接装箱单
    [attach]507[/attach]


  • OPENERP 销售invoice(无税) 源码分析
    L leetaizhu

    接上贴 点击SO003的 创建发票 按钮
    [attach]477[/attach]
    [attach]478[/attach]
    [attach]479[/attach]

    [attach]480[/attach]

    [attach]481[/attach]

    [attach]482[/attach]

    [attach]483[/attach]

    [attach]484[/attach]

    [attach]497[/attach]
    更确切的说是 1 计算发票的付款到期日 2 生成会计凭证 3 更新 发票/会计凭证/会计分录 的编号 4 更改发票的状态为 OPEN
    这里面的第一个 方法
    def action_date_assign(self, cr, uid, ids, *args):
    for inv in self.browse(cr, uid, ids):
    res = self.onchange_payment_term_date_invoice(cr, uid, inv.id, inv.payment_term.id, inv.date_invoice)
    if res and res['value']:
    self.write(cr, uid, [inv.id], res['value'])
    return True
    作用就是计算付款到期日,根据付款规则计算付款到期日

    这里面的第二个方法 是这里的核心方法 放在最后说明

    这里面的第三个方法
    def action_number(self, cr, uid, ids, *args):
    cr.execute('SELECT id, type, number, move_id, reference '
    'FROM account_invoice '
    'WHERE id IN ('+','.join(map(str,ids))+')')
    obj_inv = self.browse(cr, uid, ids)[0]
    for (id, invtype, number, move_id, reference) in cr.fetchall():
    if not number:
    if obj_inv.journal_id.invoice_sequence_id:
    sid = obj_inv.journal_id.invoice_sequence_id.id
    number = self.pool.get('ir.sequence').get_id(cr, uid, sid, 'id=%s', {'fiscalyear_id': obj_inv.period_id.fiscalyear_id.id})
    else:
    number = self.pool.get('ir.sequence').get(cr, uid,
    'account.invoice.' + invtype)
    if invtype in ('in_invoice', 'in_refund'):
    ref = reference
    else:
    ref = self._convert_ref(cr, uid, number)
    cr.execute('UPDATE account_invoice SET number=%s '
    'WHERE id=%s', (number, id))
    cr.execute('UPDATE account_move SET ref=%s '
    'WHERE id=%s AND (ref is null OR ref = '')',
    (ref, move_id))
    cr.execute('UPDATE account_move_line SET ref=%s '
    'WHERE move_id=%s AND (ref is null OR ref = '')',
    (ref, move_id))
    cr.execute('UPDATE account_analytic_line SET ref=%s '
    'FROM account_move_line '
    'WHERE account_move_line.move_id = %s '
    'AND account_analytic_line.move_id = account_move_line.id',
    (ref, move_id))
    return True
    更新 发票/会计凭证/会计分录 的编号

    在介绍第二个方法时 先说明一下它用到的一些方法
    [attach]498[/attach]

    [attach]499[/attach]

    现在到终于到第三个方法了
    [attach]500[/attach]
    [attach]501[/attach]
    [attach]502[/attach]
    [attach]503[/attach]
    [attach]504[/attach]

               [color=Red] total[/color] += i['price']
                [color=Magenta]i['price'] = - i['price'][/color]
    和 
                iml.append({
                    'type': 'dest',
                    'name': name,
                    '[color=Magenta]price[/color]'[color=Red]: total,[/color]
                    'account_id': acc_id,
                    'date_maturity' : inv.date_due or False,
                    'amount_currency': diff_currency_p 
                            and total_currency or False,
                    'currency_id': diff_currency_p 
                            and inv.currency_id.id or False,
                    'ref': ref
            })
                 这个就是 影响 debit 和 credit 
            'debit':x['[color=Magenta]price[/color]']&gt;0 and x['[color=Magenta]price[/color]'],
            'credit':x['[color=Magenta]price[/color]']&lt;0 and -x['[color=Magenta]price[/color]'],
    

    菜终于上来了 可以开动了 点击 创建 发票的按钮
    [attach]505[/attach]
    11

    [[i] 本帖最后由 leetaizhu 于 2010-3-31 15:20 编辑 [/i]]


  • OPENERP demo 测试数据分析及源码分析
    L leetaizhu

    def test_if_product(self, cr, uid, ids):
    res = True
    for production in self.browse(cr, uid, ids):
    [color=Red] if not production.product_lines:[/color]
    if not self.action_compute(cr, uid, [production.id]):
    res = False
    return res

    因为 上面 创建的 生产单里面没有 创建生产明细 所以会 执行 self.action_compute(cr, uid, [production.id])
    def action_compute(self, cr, uid, ids, properties=[]):
    results = []
    for production in self.browse(cr, uid, ids):
    cr.execute('delete from mrp_production_product_line where production_id=%s', (production.id,))
    cr.execute('delete from mrp_production_workcenter_line where production_id=%s', (production.id,))
    bom_point = production.bom_id
    bom_id = production.bom_id.id
    if not bom_point:
    bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, production.product_id.id, production.product_uom.id, properties)
    if bom_id:
    bom_point = self.pool.get('mrp.bom').browse(cr, uid, bom_id)
    routing_id = bom_point.routing_id.id or False
    self.write(cr, uid, [production.id], {'bom_id': bom_id, 'routing_id': routing_id})

            if not bom_id:
                raise osv.except_osv(_('Error'), _("Couldn't find bill of material for product"))
    
            #if bom_point.routing_id and bom_point.routing_id.location_id:
            #   self.write(cr, uid, [production.id], {'location_src_id': bom_point.routing_id.location_id.id})
    
            factor = production.product_qty * production.product_uom.factor / bom_point.product_uom.factor
    

    [color=Red] res = self.pool.get('mrp.bom')._bom_explode(cr, uid, bom_point, factor / bom_point.product_qty, properties)[/color]
    results = res[0]
    results2 = res[1]
    for line in results:
    line['production_id'] = production.id
    self.pool.get('mrp.production.product.line').create(cr, uid, line)
    for line in results2:
    line['production_id'] = production.id
    self.pool.get('mrp.production.workcenter.line').create(cr, uid, line)
    return len(results)
    这里 就把 生产单产品的BOM的产品和工作中心信息 创建到 生产单的生产明细行里和生产单的工作中心明细行里
    [attach]472[/attach]
    [attach]473[/attach]
    这之后 就执行下面的方法了
    def action_confirm(self, cr, uid, ids):
    picking_id=False
    proc_ids = []
    for production in self.browse(cr, uid, ids):
    if not production.product_lines:
    self.action_compute(cr, uid, [production.id])
    production = self.browse(cr, uid, [production.id])[0]
    routing_loc = None
    pick_type = 'internal'
    address_id = False
    if production.bom_id.routing_id and production.bom_id.routing_id.location_id:
    routing_loc = production.bom_id.routing_id.location_id
    if routing_loc.usage<>'internal':
    pick_type = 'out'
    address_id = routing_loc.address_id and routing_loc.address_id.id or False
    routing_loc = routing_loc.id
    picking_id = self.pool.get('stock.picking').create(cr, uid, {
    'origin': (production.origin or '').split(':')[0] +':'+production.name,
    'type': pick_type,
    'move_type': 'one',
    'state': 'auto',
    'address_id': address_id,
    'auto_picking': self._get_auto_picking(cr, uid, production),
    })

            source = production.product_id.product_tmpl_id.property_stock_production.id
            data = {
                'name':'PROD:'+production.name,
                'date_planned': production.date_planned,
                'product_id': production.product_id.id,
                'product_qty': production.product_qty,
                'product_uom': production.product_uom.id,
                'product_uos_qty': production.product_uos and production.product_uos_qty or False,
                'product_uos': production.product_uos and production.product_uos.id or False,
                'location_id': source,
                'location_dest_id': production.location_dest_id.id,
                'move_dest_id': production.move_prod_id.id,
                'state': 'waiting'
            }
            res_final_id = self.pool.get('stock.move').create(cr, uid, data)
    
            self.write(cr, uid, [production.id], {'move_created_ids': [(6, 0, [res_final_id])]})
            moves = []
            for line in production.product_lines:
                move_id=False
                newdate = production.date_planned
                if line.product_id.type in ('product', 'consu'):
                    res_dest_id = self.pool.get('stock.move').create(cr, uid, {
                        'name':'PROD:'+production.name,
                        'date_planned': production.date_planned,
                        'product_id': line.product_id.id,
                        'product_qty': line.product_qty,
                        'product_uom': line.product_uom.id,
                        'product_uos_qty': line.product_uos and line.product_uos_qty or False,
                        'product_uos': line.product_uos and line.product_uos.id or False,
                        'location_id': routing_loc or production.location_src_id.id,
                        'location_dest_id': source,
                        'move_dest_id': res_final_id,
                        'state': 'waiting',
                    })
                    moves.append(res_dest_id)
                    move_id = self.pool.get('stock.move').create(cr, uid, {
                        'name':'PROD:'+production.name,
                        'picking_id':picking_id,
                        'product_id': line.product_id.id,
                        'product_qty': line.product_qty,
                        'product_uom': line.product_uom.id,
                        'product_uos_qty': line.product_uos and line.product_uos_qty or False,
                        'product_uos': line.product_uos and line.product_uos.id or False,
                        'date_planned': newdate,
                        'move_dest_id': res_dest_id,
                        'location_id': production.location_src_id.id,
                        'location_dest_id': routing_loc or production.location_src_id.id,
                        'state': 'waiting',
                    })
                proc_id = self.pool.get('mrp.procurement').create(cr, uid, {
                    'name': (production.origin or '').split(':')[0] + ':' + production.name,
                    'origin': (production.origin or '').split(':')[0] + ':' + production.name,
                    'date_planned': newdate,
                    'product_id': line.product_id.id,
                    'product_qty': line.product_qty,
                    'product_uom': line.product_uom.id,
                    'product_uos_qty': line.product_uos and line.product_qty or False,
                    'product_uos': line.product_uos and line.product_uos.id or False,
                    'location_id': production.location_src_id.id,
                    'procure_method': line.product_id.procure_method,
                    'move_id': move_id,
                })
                wf_service = netsvc.LocalService("workflow")
                wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)
                proc_ids.append(proc_id)
            wf_service = netsvc.LocalService("workflow")
            wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr)
            self.write(cr, uid, [production.id], {'picking_id':picking_id, 'move_lines': [(6,0,moves)], 'state':'confirmed'})
        return picking_id
    

    这个方法比较复杂同时也是最核心的地方
    首先来 看看 这里面有三个 创建 self.pool.get('stock.move').create 的地方
    分别来看看
    第一个 self.pool.get('stock.move').create 创建是
    [attach]474[/attach]
    第二个 self.pool.get('stock.move').create 创建是
    [attach]475[/attach]
    第三个 self.pool.get('stock.move').create 创建是
    [attach]476[/attach]
    proc_id = self.pool.get('mrp.procurement').create(cr, uid, {
    'name': (production.origin or '').split(':')[0] + ':' + production.name,
    'origin': (production.origin or '').split(':')[0] + ':' + production.name,
    'date_planned': newdate,
    'product_id': line.product_id.id,
    'product_qty': line.product_qty,
    'product_uom': line.product_uom.id,
    'product_uos_qty': line.product_uos and line.product_qty or False,
    'product_uos': line.product_uos and line.product_uos.id or False,
    'location_id': production.location_src_id.id,
    'procure_method': line.product_id.procure_method,
    'move_id': move_id,
    })
    wf_service = netsvc.LocalService("workflow")
    wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)
    这里 这个 wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr) 是不是 很熟悉 对就是上面出现的 好像进入到 递归运算里了

    [[i] 本帖最后由 leetaizhu 于 2010-3-29 01:52 编辑 [/i]]


  • OPENERP demo 测试数据分析及源码分析
    L leetaizhu

    首先 需要修正一下OPENERP 5.0.7里的 产品BOM信息
    [attach]465[/attach]
    [attach]466[/attach]
    为了 简单 我们 先测试官方demo 测试数据 的 销售订单 SO003 我是在2010/03/26日创建的生产帐套
    第一我们需要取消除了 定期盘存以外其他的数据
    首先打开 pgAdmin III 里数据库
    删除 stock_picking
    mrp_procurement
    mrp_production
    mrp_production_move_ids
    mrp_production_product_line
    mrp_production_workcenter_line
    表的信息
    删除stock_move表里第16行以后的数据 (1-16行是盘点数据或者说是初始库存)
    取消 SO003,SO004,SO005的订单
    然后 审核订单 SO003 ---测试就从这里开始了
    因为SO003的 分拣策略 为分批出货 订单明细的获得方式都是 订货(MTO/来单生产)
    同时 SO003的订单明细 有 [color=Red][PC1] 基本电脑[/color] 基本电脑 3台 订单明细的交货期(Delivery Lead Time:delay) 为2天
    [color=Red][PC2] 基础+PC(按订单组装) [/color]3台 订单明细的交货期(Delivery Lead Time:delay) 为7天
    而公司的配置信息内设置了 交货安全期(company.security_lead) 为5天 依据源码
    date_planned = DateTime.now() + DateTime.DateTimeDeltaFromDays(line.delay or 0.0)
    date_planned = (date_planned - DateTime.DateTimeDeltaFromDays(company.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
    [color=Red][PC1] 基本电脑 [/color]计划时间 就是 当期时间(2010/03/26)+2天-5天 =2010/03/23
    [color=Red][PC2] 基础+PC(按订单组装)[/color] 计划时间 就是 当期时间(2010/03/26)+7天-5天 =2010/03/28
    [attach]467[/attach]

    所以 审核订单 SO003
    第一 会创建 一个出库单
    第二 会创建 1) 会和上面的出单一样的计划时间
    [attach]468[/attach]
    订单 的 审核订单按钮会执行 sale.py 里的 action_ship_create方法
    里面有
    [color=Red] wf_service = netsvc.LocalService("workflow")[/color]
    [color=Red] wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)[/color]
    [color=Red] self.pool.get('sale.order.line').write(cr, uid, [line.id], {'procurement_id': proc_id})[/color]

    上面红色字的就会 触发 需求单 里的工作流 的方法
    [attach]469[/attach]
    到 工作流 produce 里面的方法 action_produce_assign_product
    def action_produce_assign_product(self, cr, uid, ids, context={}):
    produce_id = False
    company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
    for procurement in self.browse(cr, uid, ids):
    res_id = procurement.move_id.id
    loc_id = procurement.location_id.id
    newdate = DateTime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - DateTime.RelativeDateTime(days=procurement.product_id.product_tmpl_id.produce_delay or 0.0)
    newdate = newdate - DateTime.RelativeDateTime(days=company.manufacturing_lead)
    produce_id = self.pool.get('mrp.production').create(cr, uid, {
    'origin': procurement.origin,
    'product_id': procurement.product_id.id,
    'product_qty': procurement.product_qty,
    'product_uom': procurement.product_uom.id,
    'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
    'product_uos': procurement.product_uos and procurement.product_uos.id or False,
    'location_src_id': procurement.location_id.id,
    'location_dest_id': procurement.location_id.id,
    'bom_id': procurement.bom_id and procurement.bom_id.id or False,
    'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
    'move_prod_id': res_id,
    })
    [color=Red] self.write(cr, uid, [procurement.id], {'state':'running'})[/color]
    bom_result = self.pool.get('mrp.production').action_compute(cr, uid,
    [produce_id], properties=[x.id for x in procurement.property_ids])
    wf_service = netsvc.LocalService("workflow")
    [color=Red]wf_service.trg_validate(uid, 'mrp.production', produce_id, 'button_confirm', cr)[/color]
    self.pool.get('stock.move').write(cr, uid, [res_id],
    {'location_id':procurement.location_id.id})
    return produce_id

    上面的 [color=Red]self.write(cr, uid, [procurement.id], {'state':'running'})[/color] 说明 需求单 的状态为 运行中
    [attach]470[/attach]
    根据
    newdate = DateTime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - DateTime.RelativeDateTime(days=procurement.product_id.product_tmpl_id.produce_delay or 0.0)
    newdate = newdate - DateTime.RelativeDateTime(days=company.manufacturing_lead)
    [color=Red][PC1] 基本电脑 [/color]的 procurement.date_planned为 2010/03/23 - [color=Red][PC1] 基本电脑 [/color]的生产提前期(5.0.7翻译为 制造周期)为1天(procurement.product_id.product_tmpl_id.produce_delay) -公司的生产提前期(company.manufacturing_lead) 为1天
    newdate =2010/03/21
    [color=Red][PC2] 基础+PC(按订单组装)[/color] 的 procurement.date_planned为 2010/03/28 - [color=Red][PC1] 基本电脑 [/color]的生产提前期(5.0.7翻译为 制造周期)为1天(procurement.product_id.product_tmpl_id.produce_delay) -公司的生产提前期(company.manufacturing_lead) 为1天
    newdate =2010/03/26

    [color=Red]wf_service.trg_validate(uid, 'mrp.production', produce_id, 'button_confirm', cr) [/color]会触发
    [attach]471[/attach]
    (因一个贴子的字数限制 后面的内容在下面 或下一页)

    [[i] 本帖最后由 leetaizhu 于 2010-3-28 23:50 编辑 [/i]]


  • OPENERP 财务之 Reconcile 的个人理解 请大家纠正
    L leetaizhu

    根据老肖的教程 对Reconcile的解释
    Reconcile: 可核销,通常只有应收、应付科目才勾选。勾选了的科目,系统允许通过转帐或付现进行核销。
    Reconcile: 调节
    我的理解很模糊 而且我感觉这个字段的理解在OPENERP中是很有必要 对此我做了一下功课

    第一 是 核销的概念
    [b]会计核销[/b]

    B公司经常购买A公司的货物,双方约定月结款项。以下为近几个月的业务:
    1月2日购500元。
    2月4日购800元。
    3月2日购500元。
    假若这三笔都已经挂应收B公司的应收账款,B公司一直到3月3日支付1000元的货款。那么到底这是属于还哪一笔的货款呢?这时就需要通过往来业务核销。要视具体情况而处理。
    比如这时B公司说这是支付两笔500元的业务款,那么对应就将1月2日与3月2日的两笔往来业务核销。保留2月4日的那笔。
    如果无法知道,具体给付的是哪笔业务。那就按先挂账的先销账的原则,先核销1月2日购500元,2月4日购800元,其中的500元。余2月4日的300元及3月2日的500元。

    以上所指的是应收账款的核销,当然以此类推可以应用到应付、预付、预收
    [color=#f00000]就是与有业务往来的客户或供应商之间销售或购货所发生出货或收货与收款或付款的核销业务.(PS:对某业务的审核,然后注销这笔业务,也就是说这笔业务结束了.)[/color]

    比如你单位买入一批材料,材料已到而货款未付.你的应付账款的贷方就是欠对方的货款.然后某日你货款给对方.你的应付账款借方就与贷方平了.这是账面.而往业核销功能就把这笔业务核销.这就是往来业务核销功能.
    这是转载 blog.sina.com.cn/s/blog_467a6b970100emcx.html

    第二 调节/调整
    根据我看会计书里的介绍 财务会计(原书第五版) 第三章 账户调整
    调整分录(adjusting entries)
    为了在获得收入的时候就将其入账, 在费用发生的期间将其确认, 需要在会计期末做调整分录(adjusting entries)
    调整分录的类型
    预付款项
    1) 预付费用. 以现金支付,在使用或消耗前作为资产记录的费用
    2) 预收收入. 已经收到但是作为负债加以记录的现金
    应计款项
    1)应计收入. 已取得收入但还未收到现金或记录
    2)应计费用. 已发生的费用但还未支付现金或记录


    [b]account.account.type [/b]的
    'close_method': fields.selection([('none', 'None'),
    ('balance', 'Balance'),
    ('detail', 'Detail'),
    ('unreconciled', 'Unreconciled')
    ], 'Deferral Method', required=True),

    上海-wj的解释
    * 递延方法 - Deferral Method

    1. 无——年末结转的时候不会考虑这个类型的科目
    2. 余额——年末结转时会将科目的余额转为下年的期初余额
    3. 详情——年末结转时会把该科目的凭证行逐行转入下年
    4. 未对账——年末结转时会把该科目未对账的凭证行逐行转入下年

    [[i] 本帖最后由 leetaizhu 于 2010-3-19 22:23 编辑 [/i]]


  • OPENERP ALL-IN -ONE 安装包制作过程
    L leetaizhu

    ALL IN ONE 的安装包制作成功 在这里要谢谢 OLDREV写的安装脚本


  • OPENERP ALL-IN -ONE 安装包制作过程
    L leetaizhu

    强烈求助 发截图 千行文字不如一个截图


  • OPENERP ALL-IN -ONE 安装包制作过程
    L leetaizhu

    昆明欧德瑞<[[email protected]:1ww51oa9][email protected][/email:1ww51oa9]> 给我指点迷津 和 它发给我的 安装包README

    如何使用安装脚本

    1. 请安装 OpenERP 官方提供的 All-In-One 安装包 。
    2. 复制官方程序安装目录下的所有文件到 .bin,确保 .bin 下有 server、client 和 web 三个目录。
    3. 在当前目录中执行 make.bat <版本>,make.bat 脚本将自动创建 All-In-One 安装程序。
    4. 在执行 svn add 之前记得清理所有的临时文件。

    获取 安装包制作项目 源代码

    这是下载下来的目录和 WIN32安装包脚本
    截图
    [attach]456[/attach]
    下面是 要在BIN里面放的要打包的文件
    [attach]457[/attach]

    这里还需要个软件 NSIS 它是制作安装程序的软件

    (这是修改过的 原先的帖子不正确 下面的留言是对原来的帖子进行指导)

    [[i] 本帖最后由 leetaizhu 于 2010-3-19 19:57 编辑 [/i]]


  • OPENERP 库存管理源码分析(wizard 的个人理解)
    L leetaizhu

    看了半天的关于wizard的英文开发文档 看的一头雾水 还是看源码吧 源码是最好的文档了 先冲简单开始 从 定期盘存 的 合并盘存的向导(wizard)开始吧

    [attach]437[/attach]

    点击 合并盘存 选择 是
    [attach]438[/attach]
    这里 报了个警告 请至少选择两个盘点单
    [attach]439[/attach]
    就是这么一个操作 看看源码是怎么流转和运作的

    这是 STOCK包里的 向导定义XML 模块 model="stock.inventory" 和 name="inventory.merge" 我分析这个就是会出现在盘点单右边的原因
    [attach]440[/attach]

    下面这个 就是 向导的类啦 这里的 states={ ...} 很有意思 乍一看很不适应 "init" 一出现 八九不离十 肯定是 起点 "end" 肯定是 结束了

    [attach]441[/attach]

    当选择 是 (确认合并盘存) 就会执行 do_merge 方法
    下面这个'Please select at least two inventories' 就是上面当只选择一个盘点单时 操作 合并盘存向导 执行 执行 do_merge方法 里面返回的警告信息

    [attach]442[/attach]

    下一个会找个比较复杂 例子
    这个是 POS的向导
    [attach]443[/attach]

    [[i] 本帖最后由 leetaizhu 于 2010-3-15 22:26 编辑 [/i]]


  • OPENERP WEB端源码框架分析(逐步更新中...)
    L leetaizhu

    刚进入OPENERP和PYTHON OPENERP 不到一个月 对于我来说还是一个新人 这里首先应该感谢 我们这个论坛 我通过看了里面的 知识库,一些帖子,OpenERP应用和开发基础一至六章 等 ,使我可以快速的进步可以熟练的应用OPENERP, 但我发现关于源码分析的内容比较少 ,当然这个贴子没有什么很高技术含量 是为像我一样刚进入OPENERP的新人能快速理解OPENERP的框架结构 当我刚接触OPENERP的时候 就有一个疑问它是怎么运作的,内部是怎么实现的 就像你买个电脑总想拆开看看里面到底是什么东西 好了废话就到这里吧 这个部分主要说一下 OPENERP WEB的源码架构分析
    先借老肖的图来看看
    [attach]423[/attach]
    OPENERP WEB端 与 SERVER端 通信是用 XML-RPC 和 NET-RPC ,用CHERRYPY来实现页面的响应 ,用MAKO模板技术来展现页面的内容
    如果你以前做过B/S项目的话 你会发现怎会这样 为什么WEB项目里面什么业务逻辑都没有 所以业务逻辑怎么都在OpenERP Server(业务数据库)里面
    我个人理解OpenERP Server为业务数据库 像我在07年做B/S的时候会写个页面放进去个GRID控件 指定的数据源 从数据库里读出个datatable出来 加载到GRID里 就是写个页面 然后从数据库加载数据显示出来,而OPENERP却是不用你写页面 它直接从OPENERP SERVER(业务数据库)里加载页面数据和业务数据 一起到WEB端, 再由WEB端生成页面显示业务数据同时响应用户的交互式的操作 这就像 你再好的法拉利汽车你和变形金刚大黄蜂比

    XML-RPC 和 NET-RPC 在OPENERP里的作用 让我想起 三国演义里的空城计 OPENERP WEB端就是那个阳平关城 XML-RPC和NET-RPC就是 诸葛亮弹吉他的两只手 从诸葛亮的心理(OPENERP SERVER端)弹出来 把一个空城弹的是百万兵马 呵呵 IE用户就都是司马懿了 (看上面的图用的还是电吉他)
    关于 XML-RPC 和 NET-RPC基本用法 请看看这里 www.shine-it.net/viewthread.php?tid=927&extra=page%3D1
    在以后的时间会详细分析 XML-RPC 和 NET-RPC 在OPENERP 的源码

    OPENERP WEB端 用的HTTP服务器用的是 Cherrypy 的内建 HTTP 服务器
    我们可以从python的交互式解析器里运行[attach]424[/attach]
    先 停掉 OPENERP WEB端的服务 不然会端口已占用的错误的
    [attach]425[/attach]
    下面是 我登陆 然后进入业务伙伴的TREE里的 访问日志信息
    [attach]426[/attach]
    OPENERP WEB端的 HTTP响应 基本就那么几个

    [检测到链接无效,已移除] 打开主菜单页面 [检测到链接无效,已移除] 打开某一个菜单项的页面(TREE形式的就是GRID查询的形式) ,后面都会有一些参数 例如?model=ir.ui.menu&id=84 [检测到链接无效,已移除] 打开一个表单 这里的参数会很多 例如 ?model=res.partner&id=2&ids= 等 很多参数

    还有很多这里就不一一列举 可以自己尝试一些
    这里的 menu ,tree/open,form/view 都不是实际的页面 而是类 通过 Cherrypy 可以把访问的路径比如http://localhost:8080/menu 映射到 类里的方法 ,然后方法返回基于MAKO模板生成的页面

    下面 用一个实例来说话最有说服力了
    首先看一下这个类 [attach]428[/attach]
    它是日志的装饰器(decorater) 我们为了调试方便 做点小小的修改
    把原来的36行 def profile(name, log=[], cb=None): 改成了新的 def profile(name, log=[], cb=None,result=False): 加了一个有默认值的参数
    result=False 的意思是是否输出函数返回值
    把原来的98行 logger.info(message(func, *args, **kw), extra=dct) 改成了新的
    if result:
    logger.info(message(func, *args, **kw)+"result="+str(res), extra=dct)
    else:
    logger.info(message(func, *args, **kw), extra=dct)
    这就OK了
    然后在shortcuts.py模块里的 def default(self): 上面加上日志的装饰器 @profile("leetaizhu", log=[0],cb=None,result=True)
    第一个参数是日志的文件名 ,第二个是 被装饰的函数的参数 log=[0] 里的0代表self 具体看上面的图片里的注释
    [attach]429[/attach]
    最后 一个 要改下配置文件 把注释去掉
    # Simple code profiling
    server.profile_on = True
    server.profile_dir = "profile"

    然后重新启动一下OPENERP WEB端的服务
    对个搞了半天 具体要测什么呀
    [attach]431[/attach]
    点击 SHORTCHTS链接
    [attach]433[/attach]
    下面是点击之后的日志信息 第一行 result=之后的就是 那个函数的返回值了
    [attach]432[/attach]
    通过对比它和 点击右键时的HTML源码是一样一样一样的!
    [attach]434[/attach]

    MAKO 模板界的小鲨鱼的 很是厉害 它还是混血儿 它爸是大蟒PYTHON(呵呵) 这里找到一个很好的教程 www.cnblogs.com/rchen/archive/2007/06/15/mako_doc_translation_1.html
    下面就看看 OPENERP WEB端的 MAKO 的使用吧 ...
    [attach]435[/attach]
    [attach]436[/attach]

    [[i] 本帖最后由 leetaizhu 于 2010-3-15 00:13 编辑 [/i]]


  • OPENERP XMLRPC 调试 与 NETRPC调试
    L leetaizhu

    我有一个疑问 为什么官方文档里只有XMLRPC的介绍说明及简单用法 却没有的NETRPC 调试呢 是因为NETRPC太简单了吗 因为NETRPC是大家都知道的socket
    我还有一个很大疑问 为什么 客户端(GTK/WEB)的连接方式都是 NETRPC 用 8070端口通讯 而为什么不用8069的XMLRPC呢 当然我想在配置文件里有设置参数 可以切换选择哪个RPC 但它默认安装的是NETRPC 是说明 NETRPC是现在主推的 推荐首选NETRPC
    或是在有防火墙的环境下才首选 XMLRPC吗
    下面我们来简单的调试NETRPC

    [[i] 本帖最后由 leetaizhu 于 2010-3-13 09:05 编辑 [/i]]


  • OPENERP XMLRPC 调试 与 NETRPC调试
    L leetaizhu

    OPENERP XML-RPC 调试( mrshelly 教我启蒙 )
    mrshelly 在QQ上说 可以 XML-RPC 调试 就从这里开始吧
    下面的一部分是NETRPC 调试

    [[i] 本帖最后由 leetaizhu 于 2010-3-13 08:26 编辑 [/i]]


  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    重庆-mrshelly(49812643) 16:38:53
    使用 Function 字段,基本上可以实现 凭空造数据的功能.
    重庆-mrshelly(49812643) 16:39:19
    也可用它来实现把其它数据库的数据表中的数据 整合到OE的对象中来的.


  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    oldrev的意思 是告诉我 function字段类型的 fnct_inv 的用法 . 太不好意思了 没有仔细看 同时也 谢谢digitalsatori的指导
    基于库存管理 就用 stock_picking类(模块)来简单说明一下吧


  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    function 的字段,应该不是为了速度,但它确实可以保存最新的值
    function字段我个人感觉它更像数据库中的函数
    比如 我们写一个SQL select s.no,s.name,dbo.f_数据库函数(s.id) from sample as s


  • OPENERP 库存管理源码分析(库存预警小功能)
    L leetaizhu

    大家一起来 让它支持多仓库


  • OPENERP 库存管理源码分析(库存预警小功能)
    L leetaizhu

    viewthread.php?tid=918&extra=page%3D1 基于此我们实现一个库存预警的小功能

    第一 我们先扩展mrp模块的 stock_warehouse_orderpoint 的类 它是 库存最小采购规则表
    在这里扩展两个字段 类型为功能/函数字段(Functional Field) ,产品的"实际库存"和"虚拟库存" (这里的计量单位都是默认为采购单位 所以 实际库存和虚拟库存都应该转换为采购单位-同时目前为了演示现在仅支持单仓库)
    然后为能自动显示出低于最小采购量的产品的图表(过滤出在正常库存水平的产品) 给库存管理更加直观的监控 还需要增加一个字段 "是否需要采购" 的字段 类型也为功能/函数字段(Functional Field) 同时 要在这个功能/函数字段上添加一个筛选查询的函数
    其实就是这么的简单 下面看看图片就一目了然了

    [[i] 本帖最后由 leetaizhu 于 2010-3-12 00]]


  • OPENERP 库存管理源码分析(Functional Field 的个人理解)
    L leetaizhu

    wjfonhand 说的对 就是这样 第一个参数是计算的逻辑,第二个是筛选的逻辑


  • OPENERP 库存管理源码分析(Property Fields 个人理解)
    L leetaizhu

    谢谢 digitalsatori 超级版主 的补充 这样基本就完善了 最后就差 何时应该用Fields.property 最佳实践了 希望大家一起努力

  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 标签
  • 热门
  • 用户
  • 群组